Changes to codegen to move from JS to PHP generation

master
Araozu 2023-09-08 19:34:08 -05:00
parent 94f0b0c92d
commit c61f88aaaa
8 changed files with 41 additions and 22 deletions

22
README.md Normal file
View File

@ -0,0 +1,22 @@
# THP: Typed Hypertext Processor
Types and a new syntax for PHP, because I'm forced to use it at work.
## Usage
### Singular files
Inside an existing PHP codebase, files are converted to THP
one at a time, or new files are written in THP.
There must be a thp.config.yaml at the root of the project,
which configures the compiler.
Every file is compiled in place.
### Project mode
The whole project uses THP. Work in progress.

View File

@ -2,18 +2,18 @@ use super::Transpilable;
use crate::syntax::ast::Binding; use crate::syntax::ast::Binding;
impl Transpilable for Binding { impl Transpilable for Binding {
/// Transpiles val and var bindings into JS. /// Transpiles val and var bindings into PHP.
fn transpile(&self) -> String { fn transpile(&self) -> String {
match self { match self {
Binding::Val(val_binding) => { Binding::Val(val_binding) => {
let expression_str = val_binding.expression.transpile(); let expression_str = val_binding.expression.transpile();
format!("const {} = {};", val_binding.identifier, expression_str) format!("${} = {};", val_binding.identifier, expression_str)
} }
Binding::Var(var_binding) => { Binding::Var(var_binding) => {
let expression_str = var_binding.expression.transpile(); let expression_str = var_binding.expression.transpile();
format!("let {} = {};", var_binding.identifier, expression_str) format!("${} = {};", var_binding.identifier, expression_str)
} }
} }
} }
@ -36,6 +36,6 @@ mod tests {
let result = binding.transpile(); let result = binding.transpile();
assert_eq!("const identifier = 322;", result); assert_eq!("$identifier = 322;", result);
} }
} }

View File

@ -2,7 +2,7 @@ use super::Transpilable;
use crate::syntax::ast::Expression; use crate::syntax::ast::Expression;
impl Transpilable for Expression { impl Transpilable for Expression {
/// Transpiles an Expression to JS /// Transpiles an Expression to PHP
/// ///
/// Right now the expressions in the grammar are: /// Right now the expressions in the grammar are:
/// - Number /// - Number

View File

@ -4,13 +4,13 @@ mod binding;
mod expression; mod expression;
mod module_ast; mod module_ast;
/// Trait that the AST and its nodes implement to support transformation to JavaScript /// Trait that the AST and its nodes implement to support transformation to PHP
trait Transpilable { trait Transpilable {
/// Transforms this struct into JavaScript /// Transforms this struct into PHP
fn transpile(&self) -> String; fn transpile(&self) -> String;
} }
/// Transforms an AST to its representation in JavaScript /// Transforms an AST to its representation in PHP
pub fn codegen<'a>(ast: &'a ModuleAST) -> String { pub fn codegen<'a>(ast: &'a ModuleAST) -> String {
ast.transpile() ast.transpile()
} }
@ -29,6 +29,6 @@ mod tests {
let out_str = codegen(&ast); let out_str = codegen(&ast);
assert_eq!("const id = 322;", out_str); assert_eq!("$id = 322;", out_str);
} }
} }

View File

@ -2,7 +2,7 @@ use super::Transpilable;
use crate::syntax::ast::ModuleAST; use crate::syntax::ast::ModuleAST;
impl Transpilable for ModuleAST { impl Transpilable for ModuleAST {
/// Transpiles the whole AST into JS, using this same trait on the /// Transpiles the whole AST into PHP, using this same trait on the
/// nodes and leaves of the AST /// nodes and leaves of the AST
fn transpile(&self) -> String { fn transpile(&self) -> String {
let bindings_str: Vec<String> = self let bindings_str: Vec<String> = self
@ -36,6 +36,6 @@ mod tests {
let result = module.transpile(); let result = module.transpile();
assert_eq!("const identifier = 322;", result); assert_eq!("$identifier = 322;", result);
} }
} }

View File

@ -3,7 +3,7 @@ use std::{fs, path::Path};
use crate::lexic::token::Token; use crate::lexic::token::Token;
use crate::{codegen, error_handling::PrintableError, lexic, syntax}; use crate::{codegen, error_handling::PrintableError, lexic, syntax};
pub fn compile_file(input: &String, output: &String) { pub fn compile_file(input: &String) {
let input_path = Path::new(input); let input_path = Path::new(input);
if !input_path.is_file() { if !input_path.is_file() {
@ -13,10 +13,11 @@ pub fn compile_file(input: &String, output: &String) {
let bytes = fs::read(input_path).expect("INPUT_PATH should be valid"); let bytes = fs::read(input_path).expect("INPUT_PATH should be valid");
let contents = String::from_utf8(bytes).expect("INPUT_PATH's encoding MUST be UTF-8"); let contents = String::from_utf8(bytes).expect("INPUT_PATH's encoding MUST be UTF-8");
let js_code = compile(&contents); let out_code = compile(&contents);
let output_path = Path::new(output); let mut output_path = Path::new(input).canonicalize().unwrap();
fs::write(output_path, js_code).expect("Error writing to output path"); output_path.set_extension("php");
fs::write(output_path, out_code).expect("Error writing to output path");
} }
/// Executes Lexical analysis, handles errors and calls build_ast for the next phase /// Executes Lexical analysis, handles errors and calls build_ast for the next phase

View File

@ -27,9 +27,6 @@ enum Commands {
C { C {
/// File to compile /// File to compile
file: String, file: String,
/// File to write the JS code to
output: String,
}, },
/// Starts the REPL /// Starts the REPL
R {}, R {},
@ -49,15 +46,14 @@ fn get_copyright() -> String {
/// Usage: /// Usage:
/// - `misti` : Starts the compiler in watch mode /// - `misti` : Starts the compiler in watch mode
/// - `misti w, --watch, -w` : Starts the compiler in watch mode /// - `misti w, --watch, -w` : Starts the compiler in watch mode
/// - `misti -c FILE -o OUTPUT` : Compiles FILE and writes the result in OUTPUT /// - `misti c FILE` : Compiles FILE and writes the result in the same directory
fn main() { fn main() {
let cli = Cli::parse(); let cli = Cli::parse();
match &cli.command { match &cli.command {
Some(Commands::C { Some(Commands::C {
file: input, file: input,
output, }) => file::compile_file(input),
}) => file::compile_file(input, output),
Some(Commands::R {}) => { Some(Commands::R {}) => {
println!("{}", get_copyright()); println!("{}", get_copyright());
let _ = repl::run(); let _ = repl::run();

View File

@ -40,7 +40,7 @@ fn build_ast(input: &String, tokens: Vec<Token>) {
} }
} }
/// Executes the REPL, reading from stdin, compiling and emitting JS to stdout /// Executes the REPL, reading from stdin, compiling and emitting PHP to stdout
pub fn run() -> io::Result<()> { pub fn run() -> io::Result<()> {
let stdin = io::stdin(); let stdin = io::stdin();
let mut buffer = String::new(); let mut buffer = String::new();