Compare commits

..

2 Commits

Author SHA1 Message Date
Araozu 0d96efd4d8 Minimal workflow for a Hello World 2024-07-27 18:44:54 -05:00
Araozu fe7cfe9d5f feat: Minimal conversion of THP->PHP AST 2024-07-27 17:34:32 -05:00
12 changed files with 202 additions and 17 deletions

View File

@ -23,13 +23,20 @@
- Include the original tokens in the AST - Include the original tokens in the AST
## v0.0.15
- [ ] Replace all panics with actual errors
- [ ] Remove all old codegen
- [ ] Test codegen
- [ ] Begin work on the code formatter
## v0.0.14 ## v0.0.14
- [ ] Define a minimal PHP AST - [x] Define a minimal PHP AST
- [ ] Transform THP AST into PHP AST - [x] Transform THP AST into PHP AST
- [ ] Implement minimal codegen for the PHP AST - [x] Implement minimal codegen for the PHP AST
- [ ] Remove old codegen - [x] Finish the workflow for a hello world
- [ ] Finish the workflow for a hello world
## v0.0.13 ## v0.0.13

View File

@ -1,6 +1,6 @@
[package] [package]
name = "thp" name = "thp"
version = "0.0.13" version = "0.0.14"
edition = "2021" edition = "2021"

View File

@ -1,5 +1,5 @@
use std::io::{self, BufRead};
use crate::lexic::get_tokens; use crate::lexic::get_tokens;
use std::io::{self, BufRead};
pub fn tokenize_command(_options: Vec<String>) -> Result<(), ()> { pub fn tokenize_command(_options: Vec<String>) -> Result<(), ()> {
// Get the input from stdin // Get the input from stdin
@ -8,12 +8,10 @@ pub fn tokenize_command(_options: Vec<String>) -> Result<(), ()> {
let mut lines = Vec::new(); let mut lines = Vec::new();
for line in stdin.lock().lines() { for line in stdin.lock().lines() {
match line { match line {
Ok(line) => { Ok(line) => lines.push(line),
lines.push(line)
}
Err(reason) => { Err(reason) => {
eprintln!("Error reading input: {}", reason); eprintln!("Error reading input: {}", reason);
return Err(()) return Err(());
} }
} }
} }

View File

@ -1,5 +1,5 @@
use crate::syntax::ast::ModuleAST; // TODO: These are for the THP AST. Eventually replace this
// with the PHP AST
mod binding; mod binding;
mod block; mod block;
mod expression; mod expression;
@ -9,13 +9,15 @@ mod module_ast;
mod statement; mod statement;
mod top_level_construct; mod top_level_construct;
mod php;
/// Trait that the AST and its nodes implement to support transformation to PHP /// Trait that the AST and its nodes implement to support transformation to PHP
trait Transpilable { pub trait Transpilable {
/// Transforms this struct into PHP /// Transforms this struct into PHP
fn transpile(&self) -> String; fn transpile(&self) -> String;
} }
/// Transforms an AST to its representation in PHP /// Transforms an AST to its representation in PHP
pub fn codegen<'a>(ast: &'a ModuleAST) -> String { pub fn codegen<'a>(ast: &'a impl Transpilable) -> String {
ast.transpile() ast.transpile()
} }

50
src/codegen/php/mod.rs Normal file
View File

@ -0,0 +1,50 @@
use std::os::linux::raw::stat;
use crate::php_ast::{PhpAst, PhpExpression, PhpStatement};
use super::Transpilable;
impl Transpilable for PhpAst<'_> {
fn transpile(&self) -> String {
let mut fragments = vec![String::from("<?php\n")];
for statement in self.statements.iter() {
fragments.push(statement.transpile());
}
fragments.join("")
}
}
impl Transpilable for PhpStatement<'_> {
fn transpile(&self) -> String {
match self {
PhpStatement::PhpEchoStatement(expr_list) => {
let expressions_vec = expr_list.expressions
.iter()
.map(|e| e.transpile())
.collect::<Vec<_>>();
let expressions_str = if expressions_vec.is_empty() {
"\"\"".into()
} else {
expressions_vec.join(", ")
};
format!("echo {};", expressions_str)
}
}
}
}
impl Transpilable for PhpExpression<'_> {
fn transpile(&self) -> String {
match self {
PhpExpression::String(value) => {
format!("{}", value)
}
}
}
}

View File

@ -1,3 +1,20 @@
// Follows https://phplang.org/spec/19-grammar.html#syntactic-grammar // Follows https://phplang.org/spec/19-grammar.html#syntactic-grammar
struct PhpAst {} pub mod transformers;
/// Represents `statement-list` on the grammar
pub struct PhpAst<'a> {
pub statements: Vec<PhpStatement<'a>>,
}
pub enum PhpStatement<'a> {
PhpEchoStatement(PhpExpressionList<'a>),
}
pub struct PhpExpressionList<'a> {
pub expressions: Vec<PhpExpression<'a>>,
}
pub enum PhpExpression<'a> {
String(&'a String),
}

View File

@ -0,0 +1,16 @@
use super::super::PhpExpression;
use crate::syntax::ast::Expression;
use super::PHPTransformable;
/// Transforms a THP expression into a PHP expression
impl<'a> PHPTransformable<'a> for Expression<'_> {
type Item = PhpExpression<'a>;
fn into_php_ast(&'a self) -> Self::Item {
match self {
Expression::String(value) => PhpExpression::String(value),
_ => todo!("transformation for expression: {:?}", self),
}
}
}

View File

@ -0,0 +1,10 @@
pub mod expression;
pub mod module_ast;
pub mod statement;
/// Implemented by AST nodes that can be transformed to PHP
pub trait PHPTransformable<'a> {
type Item;
fn into_php_ast(&'a self) -> Self::Item;
}

View File

@ -0,0 +1,61 @@
use super::super::PhpAst;
use crate::php_ast::{PhpExpression, PhpExpressionList, PhpStatement};
use crate::syntax::ast::{Expression, ModuleAST, ModuleMembers};
use super::PHPTransformable;
/// Transforms a THP AST into a PHP AST
impl<'a> PHPTransformable<'a> for ModuleAST<'_> {
type Item = PhpAst<'a>;
fn into_php_ast(&'a self) -> Self::Item {
let mut php_statements = Vec::<PhpStatement>::new();
for production in self.productions.iter() {
match production {
ModuleMembers::Stmt(stmt) => {
php_statements.push(stmt.into_php_ast());
}
ModuleMembers::Expr(expr) => {
// TODO: This should be done by the Expression transformer
match expr {
Expression::FunctionCall(fc) => {
let function_expr: &Expression = &*fc.function;
match function_expr {
Expression::Identifier(id) if *id == "print" => {
// transform to print() expression
// no parameters supported
// transform parameters, expect them all to be strings
let mut expressions = Vec::<PhpExpression>::new();
for e in fc.arguments.arguments.iter() {
match e {
Expression::String(v) => {
expressions.push(PhpExpression::String(v))
},
_ => panic!("Non string expressions not supported")
}
}
php_statements.push(PhpStatement::PhpEchoStatement(PhpExpressionList {
expressions
}));
},
_ => todo!("Not implemented: AST transformation for function call that is not an identifier")
}
}
_ => {
todo!("not implemented: AST transform for expression {:?}", expr)
}
}
}
}
}
PhpAst {
statements: php_statements,
}
}
}

View File

@ -0,0 +1,15 @@
use super::super::PhpStatement;
use crate::syntax::ast::Statement;
use super::PHPTransformable;
/// Transforms a THP expression into a PHP expression
impl<'a> PHPTransformable<'a> for Statement<'_> {
type Item = PhpStatement<'a>;
fn into_php_ast(&'a self) -> Self::Item {
match self {
_ => todo!("transformation for statement: {:?}", self),
}
}
}

View File

@ -2,6 +2,7 @@ use std::io::{self, Write};
use colored::Colorize; use colored::Colorize;
use crate::codegen::Transpilable;
use crate::error_handling::PrintableError; use crate::error_handling::PrintableError;
use crate::lexic::token::Token; use crate::lexic::token::Token;
@ -9,6 +10,8 @@ use super::codegen;
use super::lexic; use super::lexic;
use super::syntax; use super::syntax;
use crate::php_ast::transformers::PHPTransformable;
/// 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
fn compile(input: &String) { fn compile(input: &String) {
let tokens = lexic::get_tokens(input); let tokens = lexic::get_tokens(input);
@ -32,7 +35,9 @@ fn build_ast(input: &String, tokens: Vec<Token>) {
match ast { match ast {
Ok(ast) => { Ok(ast) => {
/*
let res1 = crate::semantic::check_semantics(&ast); let res1 = crate::semantic::check_semantics(&ast);
TODO: Disabled to test the PHP codegen. Reenable
match res1 { match res1 {
Ok(_) => {} Ok(_) => {}
Err(reason) => { Err(reason) => {
@ -42,8 +47,10 @@ fn build_ast(input: &String, tokens: Vec<Token>) {
return; return;
} }
} }
*/
let js_code = codegen::codegen(&ast); let php_ast = ast.into_php_ast();
let js_code = php_ast.transpile();
println!("{}", js_code) println!("{}", js_code)
} }
Err(reason) => { Err(reason) => {

View File

@ -62,6 +62,8 @@ pub struct Parameter<'a> {
pub enum Expression<'a> { pub enum Expression<'a> {
Int(&'a String), Int(&'a String),
Float(&'a String), Float(&'a String),
// TODO: Specify if this contains or not the original quotes ""
// TODO: After this fix where neccesary
String(&'a String), String(&'a String),
Boolean(bool), Boolean(bool),
Identifier(&'a String), Identifier(&'a String),