Compare commits
2 Commits
5102d25676
...
0d96efd4d8
Author | SHA1 | Date | |
---|---|---|---|
0d96efd4d8 | |||
fe7cfe9d5f |
17
CHANGELOG.md
17
CHANGELOG.md
@ -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
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
[package]
|
[package]
|
||||||
name = "thp"
|
name = "thp"
|
||||||
version = "0.0.13"
|
version = "0.0.14"
|
||||||
edition = "2021"
|
edition = "2021"
|
||||||
|
|
||||||
|
|
||||||
|
@ -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(());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -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
50
src/codegen/php/mod.rs
Normal 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)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
@ -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),
|
||||||
|
}
|
||||||
|
16
src/php_ast/transformers/expression.rs
Normal file
16
src/php_ast/transformers/expression.rs
Normal 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),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
10
src/php_ast/transformers/mod.rs
Normal file
10
src/php_ast/transformers/mod.rs
Normal 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;
|
||||||
|
}
|
61
src/php_ast/transformers/module_ast.rs
Normal file
61
src/php_ast/transformers/module_ast.rs
Normal 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,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
15
src/php_ast/transformers/statement.rs
Normal file
15
src/php_ast/transformers/statement.rs
Normal 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),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -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) => {
|
||||||
|
@ -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),
|
||||||
|
Loading…
Reference in New Issue
Block a user