@@ -26,3 +26,4 @@ target
|
|||||||
/target
|
/target
|
||||||
|
|
||||||
/test/build
|
/test/build
|
||||||
|
/test/output.json
|
||||||
+3
-2
@@ -41,7 +41,7 @@ pub fn build() {
|
|||||||
|
|
||||||
let ast = match parser::parse(&source) {
|
let ast = match parser::parse(&source) {
|
||||||
Ok(ast) => {
|
Ok(ast) => {
|
||||||
println!(" ✓ parsed {} items", ast.statements.len());
|
println!(" ✓ parsed {} items", ast.len());
|
||||||
ast
|
ast
|
||||||
}
|
}
|
||||||
Err(e) => {
|
Err(e) => {
|
||||||
@@ -52,7 +52,8 @@ pub fn build() {
|
|||||||
|
|
||||||
println!(" → generating Go code...");
|
println!(" → generating Go code...");
|
||||||
|
|
||||||
let output = gogen::generate(&ast);
|
// let output = gogen::generate(&ast);
|
||||||
|
let output = String::from("// TODO: implement code generation\n");
|
||||||
|
|
||||||
// 4. ensure build dir
|
// 4. ensure build dir
|
||||||
if let Err(e) = fs::create_dir_all(&out_dir) {
|
if let Err(e) = fs::create_dir_all(&out_dir) {
|
||||||
|
|||||||
+229
-229
@@ -1,283 +1,283 @@
|
|||||||
use crate::parser::ast::{
|
// use crate::parser::ast::{
|
||||||
BinOperator, Class, Expression, Function, Program, Statement, Struct, TopLevel, TypeExpr,
|
// BinOperator, Class, Expression, Function, Statement, Struct, TopLevel, TopLevel, TypeExpr,
|
||||||
};
|
// };
|
||||||
|
|
||||||
pub fn generate(program: &Program) -> String {
|
// pub fn generate(program: &TopLevel) -> String {
|
||||||
let mut out = String::new();
|
// let mut out = String::new();
|
||||||
|
|
||||||
out.push_str("package main\n\n");
|
// out.push_str("package main\n\n");
|
||||||
|
|
||||||
// imports
|
// // imports
|
||||||
let mut imports = vec![];
|
// let mut imports = vec![];
|
||||||
for item in &program.statements {
|
// for item in &program.statements {
|
||||||
if let TopLevel::Import(i) = item {
|
// if let TopLevel::Import(i) = item {
|
||||||
imports.push(i.path.clone());
|
// imports.push(i.path.clone());
|
||||||
}
|
// }
|
||||||
}
|
// }
|
||||||
|
|
||||||
if !imports.is_empty() {
|
// if !imports.is_empty() {
|
||||||
out.push_str("import (\n");
|
// out.push_str("import (\n");
|
||||||
for imp in imports {
|
// for imp in imports {
|
||||||
out.push_str(&format!(" {}\n", imp));
|
// out.push_str(&format!(" {}\n", imp));
|
||||||
}
|
// }
|
||||||
out.push_str(")\n\n");
|
// out.push_str(")\n\n");
|
||||||
}
|
// }
|
||||||
|
|
||||||
// rest
|
// // rest
|
||||||
for item in &program.statements {
|
// for item in &program.statements {
|
||||||
match item {
|
// match item {
|
||||||
TopLevel::Function(f) => out.push_str(&gen_function(f)),
|
// TopLevel::Function(f) => out.push_str(&gen_function(f)),
|
||||||
TopLevel::Struct(s) => out.push_str(&gen_struct(s)),
|
// TopLevel::Struct(s) => out.push_str(&gen_struct(s)),
|
||||||
TopLevel::Class(c) => out.push_str(&gen_class(c)),
|
// TopLevel::Class(c) => out.push_str(&gen_class(c)),
|
||||||
TopLevel::Import(_) => {}
|
// TopLevel::Import(_) => {}
|
||||||
}
|
// }
|
||||||
out.push('\n');
|
// out.push('\n');
|
||||||
}
|
// }
|
||||||
|
|
||||||
out
|
// out
|
||||||
}
|
// }
|
||||||
|
|
||||||
fn gen_struct(s: &Struct) -> String {
|
// fn gen_struct(s: &Struct) -> String {
|
||||||
let mut out = format!("type {} struct {{\n", s.name);
|
// let mut out = format!("type {} struct {{\n", s.name);
|
||||||
|
|
||||||
for field in &s.fields {
|
// for field in &s.fields {
|
||||||
out.push_str(&format!(
|
// out.push_str(&format!(
|
||||||
" {} {}\n",
|
// " {} {}\n",
|
||||||
capitalize(&field.name),
|
// capitalize(&field.name),
|
||||||
gen_type(&field.type_expr)
|
// gen_type(&field.type_expr)
|
||||||
));
|
// ));
|
||||||
}
|
// }
|
||||||
|
|
||||||
out.push_str("}\n");
|
// out.push_str("}\n");
|
||||||
out
|
// out
|
||||||
}
|
// }
|
||||||
|
|
||||||
fn gen_class(c: &Class) -> String {
|
// fn gen_class(c: &Class) -> String {
|
||||||
let mut out = String::new();
|
// let mut out = String::new();
|
||||||
|
|
||||||
// struct
|
// // struct
|
||||||
out.push_str(&format!("type {} struct {{\n", c.name));
|
// out.push_str(&format!("type {} struct {{\n", c.name));
|
||||||
for field in &c.fields {
|
// for field in &c.fields {
|
||||||
out.push_str(&format!(
|
// out.push_str(&format!(
|
||||||
" {} {}\n",
|
// " {} {}\n",
|
||||||
capitalize(&field.name),
|
// capitalize(&field.name),
|
||||||
gen_type(&field.type_expr)
|
// gen_type(&field.type_expr)
|
||||||
));
|
// ));
|
||||||
}
|
// }
|
||||||
out.push_str("}\n\n");
|
// out.push_str("}\n\n");
|
||||||
|
|
||||||
// methods
|
// // methods
|
||||||
for method in &c.methods {
|
// for method in &c.methods {
|
||||||
out.push_str(&gen_method(c, method));
|
// out.push_str(&gen_method(c, method));
|
||||||
out.push('\n');
|
// out.push('\n');
|
||||||
}
|
// }
|
||||||
|
|
||||||
out
|
// out
|
||||||
}
|
// }
|
||||||
|
|
||||||
fn gen_function(f: &Function) -> String {
|
// fn gen_function(f: &Function) -> String {
|
||||||
let mut out = format!("func {}(", f.name);
|
// let mut out = format!("func {}(", f.name);
|
||||||
|
|
||||||
// params
|
// // params
|
||||||
for (i, p) in f.params.iter().enumerate() {
|
// for (i, p) in f.params.iter().enumerate() {
|
||||||
if i > 0 {
|
// if i > 0 {
|
||||||
out.push_str(", ");
|
// out.push_str(", ");
|
||||||
}
|
// }
|
||||||
out.push_str(&format!("{} {}", p.name, gen_type(&p.type_expr)));
|
// out.push_str(&format!("{} {}", p.name, gen_type(&p.type_expr)));
|
||||||
}
|
// }
|
||||||
|
|
||||||
out.push(')');
|
// out.push(')');
|
||||||
|
|
||||||
// return
|
// // return
|
||||||
if let Some(ret) = &f.return_type {
|
// if let Some(ret) = &f.return_type {
|
||||||
out.push_str(&format!(" {}", gen_type(ret)));
|
// out.push_str(&format!(" {}", gen_type(ret)));
|
||||||
}
|
// }
|
||||||
|
|
||||||
out.push_str(" {\n");
|
// out.push_str(" {\n");
|
||||||
|
|
||||||
for stmt in &f.body {
|
// for stmt in &f.body {
|
||||||
out.push_str(&gen_statement(stmt));
|
// out.push_str(&gen_statement(stmt));
|
||||||
}
|
// }
|
||||||
|
|
||||||
out.push_str("}\n");
|
// out.push_str("}\n");
|
||||||
out
|
// out
|
||||||
}
|
// }
|
||||||
|
|
||||||
fn gen_method(class: &Class, f: &Function) -> String {
|
// fn gen_method(class: &Class, f: &Function) -> String {
|
||||||
let mut out = format!("func (self *{}) {}(", class.name, f.name);
|
// let mut out = format!("func (self *{}) {}(", class.name, f.name);
|
||||||
|
|
||||||
for (i, p) in f.params.iter().enumerate() {
|
// for (i, p) in f.params.iter().enumerate() {
|
||||||
if i > 0 {
|
// if i > 0 {
|
||||||
out.push_str(", ");
|
// out.push_str(", ");
|
||||||
}
|
// }
|
||||||
out.push_str(&format!("{} {}", p.name, gen_type(&p.type_expr)));
|
// out.push_str(&format!("{} {}", p.name, gen_type(&p.type_expr)));
|
||||||
}
|
// }
|
||||||
|
|
||||||
out.push(')');
|
// out.push(')');
|
||||||
|
|
||||||
if let Some(ret) = &f.return_type {
|
// if let Some(ret) = &f.return_type {
|
||||||
out.push_str(&format!(" {}", gen_type(ret)));
|
// out.push_str(&format!(" {}", gen_type(ret)));
|
||||||
}
|
// }
|
||||||
|
|
||||||
out.push_str(" {\n");
|
// out.push_str(" {\n");
|
||||||
|
|
||||||
for stmt in &f.body {
|
// for stmt in &f.body {
|
||||||
out.push_str(&gen_statement(stmt));
|
// out.push_str(&gen_statement(stmt));
|
||||||
}
|
// }
|
||||||
|
|
||||||
out.push_str("}\n");
|
// out.push_str("}\n");
|
||||||
|
|
||||||
out
|
// out
|
||||||
}
|
// }
|
||||||
|
|
||||||
fn gen_statement(stmt: &Statement) -> String {
|
// fn gen_statement(stmt: &Statement) -> String {
|
||||||
match stmt {
|
// match stmt {
|
||||||
Statement::Let(s) => {
|
// Statement::Let(s) => {
|
||||||
let mut out = format!(" {} := {}", s.name, gen_expr(&s.value));
|
// let mut out = format!(" {} := {}", s.name, gen_expr(&s.value));
|
||||||
|
|
||||||
out.push_str(";\n");
|
// out.push_str(";\n");
|
||||||
out
|
// out
|
||||||
}
|
// }
|
||||||
|
|
||||||
Statement::Return(r) => match &r.value {
|
// Statement::Return(r) => match &r.value {
|
||||||
Some(v) => format!(" return {};\n", gen_expr(v)),
|
// Some(v) => format!(" return {};\n", gen_expr(v)),
|
||||||
None => " return;\n".to_string(),
|
// None => " return;\n".to_string(),
|
||||||
},
|
// },
|
||||||
|
|
||||||
Statement::Expression(e) => {
|
// Statement::Expression(e) => {
|
||||||
format!(" {};\n", gen_expr(e))
|
// format!(" {};\n", gen_expr(e))
|
||||||
}
|
// }
|
||||||
|
|
||||||
Statement::If(i) => {
|
// Statement::If(i) => {
|
||||||
let mut out = format!(" if {} {{\n", gen_expr(&i.condition));
|
// let mut out = format!(" if {} {{\n", gen_expr(&i.condition));
|
||||||
|
|
||||||
for stmt in &i.body {
|
// for stmt in &i.body {
|
||||||
out.push_str(&gen_statement(stmt));
|
// out.push_str(&gen_statement(stmt));
|
||||||
}
|
// }
|
||||||
|
|
||||||
out.push_str(" }");
|
// out.push_str(" }");
|
||||||
|
|
||||||
if let Some(else_body) = &i.else_body {
|
// if let Some(else_body) = &i.else_body {
|
||||||
out.push_str(" else {\n");
|
// out.push_str(" else {\n");
|
||||||
for stmt in else_body {
|
// for stmt in else_body {
|
||||||
out.push_str(&gen_statement(stmt));
|
// out.push_str(&gen_statement(stmt));
|
||||||
}
|
// }
|
||||||
out.push_str(" }");
|
// out.push_str(" }");
|
||||||
}
|
// }
|
||||||
|
|
||||||
out.push('\n');
|
// out.push('\n');
|
||||||
out
|
// out
|
||||||
}
|
// }
|
||||||
|
|
||||||
Statement::For(f) => {
|
// Statement::For(f) => {
|
||||||
let mut out = format!(
|
// let mut out = format!(
|
||||||
" for _, {} := range {} {{\n",
|
// " for _, {} := range {} {{\n",
|
||||||
f.var,
|
// f.var,
|
||||||
gen_expr(&f.iterator)
|
// gen_expr(&f.iterator)
|
||||||
);
|
// );
|
||||||
|
|
||||||
for stmt in &f.body {
|
// for stmt in &f.body {
|
||||||
out.push_str(&gen_statement(stmt));
|
// out.push_str(&gen_statement(stmt));
|
||||||
}
|
// }
|
||||||
|
|
||||||
out.push_str(" }\n");
|
// out.push_str(" }\n");
|
||||||
out
|
// out
|
||||||
}
|
// }
|
||||||
}
|
// }
|
||||||
}
|
// }
|
||||||
|
|
||||||
fn gen_expr(expr: &Expression) -> String {
|
// fn gen_expr(expr: &Expression) -> String {
|
||||||
match expr {
|
// match expr {
|
||||||
Expression::Identifier(name, _) => name.clone(),
|
// Expression::Identifier(name, _) => name.clone(),
|
||||||
Expression::Integer(v, _) => v.to_string(),
|
// Expression::Integer(v, _) => v.to_string(),
|
||||||
Expression::Float(v, _) => v.to_string(),
|
// Expression::Float(v, _) => v.to_string(),
|
||||||
Expression::StringLit(s, _) => format!("\"{}\"", s),
|
// Expression::StringLit(s, _) => format!("\"{}\"", s),
|
||||||
Expression::Bool(b, _) => b.to_string(),
|
// Expression::Bool(b, _) => b.to_string(),
|
||||||
|
|
||||||
Expression::BinaryOp(b) => format!(
|
// Expression::BinaryOp(b) => format!(
|
||||||
"{} {} {}",
|
// "{} {} {}",
|
||||||
gen_expr(&b.left),
|
// gen_expr(&b.left),
|
||||||
op_to_str(&b.op),
|
// op_to_str(&b.op),
|
||||||
gen_expr(&b.right)
|
// gen_expr(&b.right)
|
||||||
),
|
// ),
|
||||||
|
|
||||||
Expression::Call(c) => {
|
// Expression::Call(c) => {
|
||||||
let args = c.args.iter().map(gen_expr).collect::<Vec<_>>().join(", ");
|
// let args = c.args.iter().map(gen_expr).collect::<Vec<_>>().join(", ");
|
||||||
format!("{}({})", gen_expr(&c.callee), args)
|
// format!("{}({})", gen_expr(&c.callee), args)
|
||||||
}
|
// }
|
||||||
|
|
||||||
Expression::FieldAccess(f) => {
|
// Expression::FieldAccess(f) => {
|
||||||
format!("{}.{}", gen_expr(&f.object), capitalize(&f.field))
|
// format!("{}.{}", gen_expr(&f.object), capitalize(&f.field))
|
||||||
}
|
// }
|
||||||
|
|
||||||
Expression::StructInit(s) => {
|
// Expression::StructInit(s) => {
|
||||||
let mut out = format!("{}{{", s.name);
|
// let mut out = format!("{}{{", s.name);
|
||||||
|
|
||||||
for (i, (name, val)) in s.fields.iter().enumerate() {
|
// for (i, (name, val)) in s.fields.iter().enumerate() {
|
||||||
if i > 0 {
|
// if i > 0 {
|
||||||
out.push_str(", ");
|
// out.push_str(", ");
|
||||||
}
|
// }
|
||||||
out.push_str(&format!("{}: {}", capitalize(name), gen_expr(val)));
|
// out.push_str(&format!("{}: {}", capitalize(name), gen_expr(val)));
|
||||||
}
|
// }
|
||||||
|
|
||||||
out.push('}');
|
// out.push('}');
|
||||||
out
|
// out
|
||||||
}
|
// }
|
||||||
|
|
||||||
Expression::ArrayLiteral(arr) => {
|
// Expression::ArrayLiteral(arr) => {
|
||||||
let elems = arr
|
// let elems = arr
|
||||||
.elements
|
// .elements
|
||||||
.iter()
|
// .iter()
|
||||||
.map(gen_expr)
|
// .map(gen_expr)
|
||||||
.collect::<Vec<_>>()
|
// .collect::<Vec<_>>()
|
||||||
.join(", ");
|
// .join(", ");
|
||||||
format!("[]any{{{}}}", elems) // simple version
|
// format!("[]any{{{}}}", elems) // simple version
|
||||||
}
|
// }
|
||||||
|
|
||||||
_ => todo!(),
|
// _ => todo!(),
|
||||||
}
|
// }
|
||||||
}
|
// }
|
||||||
|
|
||||||
fn gen_type(t: &TypeExpr) -> String {
|
// fn gen_type(t: &TypeExpr) -> String {
|
||||||
match t {
|
// match t {
|
||||||
TypeExpr::Named(n) => match n.as_str() {
|
// TypeExpr::Named(n) => match n.as_str() {
|
||||||
"int" => "int".into(),
|
// "int" => "int".into(),
|
||||||
"float" => "float64".into(),
|
// "float" => "float64".into(),
|
||||||
"string" => "string".into(),
|
// "string" => "string".into(),
|
||||||
_ => n.clone(),
|
// _ => n.clone(),
|
||||||
},
|
// },
|
||||||
|
|
||||||
TypeExpr::Array(inner) => {
|
// TypeExpr::Array(inner) => {
|
||||||
format!("[]{}", gen_type(inner))
|
// format!("[]{}", gen_type(inner))
|
||||||
}
|
// }
|
||||||
|
|
||||||
TypeExpr::Optional(inner) => {
|
// TypeExpr::Optional(inner) => {
|
||||||
format!("*{}", gen_type(inner)) // pointer for optional
|
// format!("*{}", gen_type(inner)) // pointer for optional
|
||||||
}
|
// }
|
||||||
}
|
// }
|
||||||
}
|
// }
|
||||||
|
|
||||||
fn capitalize(s: &str) -> String {
|
// fn capitalize(s: &str) -> String {
|
||||||
let mut chars = s.chars();
|
// let mut chars = s.chars();
|
||||||
match chars.next() {
|
// match chars.next() {
|
||||||
Some(c) => c.to_uppercase().collect::<String>() + chars.as_str(),
|
// Some(c) => c.to_uppercase().collect::<String>() + chars.as_str(),
|
||||||
None => String::new(),
|
// None => String::new(),
|
||||||
}
|
// }
|
||||||
}
|
// }
|
||||||
|
|
||||||
fn op_to_str(op: &BinOperator) -> &'static str {
|
// fn op_to_str(op: &BinOperator) -> &'static str {
|
||||||
match op {
|
// match op {
|
||||||
BinOperator::Add => "+",
|
// BinOperator::Add => "+",
|
||||||
BinOperator::Sub => "-",
|
// BinOperator::Sub => "-",
|
||||||
BinOperator::Mul => "*",
|
// BinOperator::Mul => "*",
|
||||||
BinOperator::Div => "/",
|
// BinOperator::Div => "/",
|
||||||
BinOperator::Eq => "==",
|
// BinOperator::Eq => "==",
|
||||||
BinOperator::NotEq => "!=",
|
// BinOperator::NotEq => "!=",
|
||||||
BinOperator::Lt => "<",
|
// BinOperator::Lt => "<",
|
||||||
BinOperator::Gt => ">",
|
// BinOperator::Gt => ">",
|
||||||
BinOperator::LtEq => "<=",
|
// BinOperator::LtEq => "<=",
|
||||||
BinOperator::GtEq => ">=",
|
// BinOperator::GtEq => ">=",
|
||||||
BinOperator::And => "&&",
|
// BinOperator::And => "&&",
|
||||||
BinOperator::Or => "||",
|
// BinOperator::Or => "||",
|
||||||
}
|
// }
|
||||||
}
|
// }
|
||||||
|
|||||||
+27
@@ -30,6 +30,13 @@ fn main() {
|
|||||||
}
|
}
|
||||||
cmd_check(&args[2]);
|
cmd_check(&args[2]);
|
||||||
}
|
}
|
||||||
|
"parse" => {
|
||||||
|
if args.len() < 3 {
|
||||||
|
eprintln!("error: expected a file path\n usage: mist check <file.ms>");
|
||||||
|
process::exit(1);
|
||||||
|
}
|
||||||
|
cmd_parse(&args[2]);
|
||||||
|
}
|
||||||
"version" | "--version" | "-v" => {
|
"version" | "--version" | "-v" => {
|
||||||
println!("mist {}", env!("CARGO_PKG_VERSION"));
|
println!("mist {}", env!("CARGO_PKG_VERSION"));
|
||||||
}
|
}
|
||||||
@@ -61,6 +68,26 @@ fn cmd_check(path: &str) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn cmd_parse(path: &str) {
|
||||||
|
let source = read_ms_file(path);
|
||||||
|
match parser::parse(&source) {
|
||||||
|
Ok(output) => {
|
||||||
|
fs::write(
|
||||||
|
"output.json",
|
||||||
|
serde_json::to_string_pretty(&output).unwrap(),
|
||||||
|
)
|
||||||
|
.unwrap_or_else(|e| {
|
||||||
|
eprintln!("error: could not write output.json: {}", e);
|
||||||
|
process::exit(1);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
Err(e) => {
|
||||||
|
eprintln!("parse error:\n{}", e);
|
||||||
|
process::exit(1);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
fn read_ms_file(path: &str) -> String {
|
fn read_ms_file(path: &str) -> String {
|
||||||
let pb = PathBuf::from(path);
|
let pb = PathBuf::from(path);
|
||||||
|
|
||||||
|
|||||||
+118
-180
@@ -1,187 +1,125 @@
|
|||||||
#[derive(Debug, Clone)]
|
use serde::Serialize;
|
||||||
pub struct Span {
|
|
||||||
pub start: usize,
|
|
||||||
pub end: usize,
|
|
||||||
}
|
|
||||||
|
|
||||||
#[derive(Debug, Clone)]
|
#[derive(Debug, Clone, Serialize)]
|
||||||
pub struct Program {
|
pub struct ParamList(pub Vec<(String, TypeExpr)>);
|
||||||
pub statements: Vec<TopLevel>,
|
|
||||||
}
|
|
||||||
|
|
||||||
#[derive(Debug, Clone)]
|
#[derive(Debug, Clone, Serialize)]
|
||||||
pub enum TopLevel {
|
pub struct Block(pub Vec<Statement>);
|
||||||
Function(Function),
|
|
||||||
Struct(Struct),
|
|
||||||
Class(Class),
|
|
||||||
Import(Import),
|
|
||||||
}
|
|
||||||
|
|
||||||
#[derive(Debug, Clone)]
|
#[derive(Debug, Clone, Serialize)]
|
||||||
pub struct Function {
|
#[serde(tag = "type", content = "value")]
|
||||||
pub name: String,
|
|
||||||
pub params: Vec<Param>,
|
|
||||||
pub return_type: Option<TypeExpr>,
|
|
||||||
pub body: Vec<Statement>,
|
|
||||||
pub span: Span,
|
|
||||||
}
|
|
||||||
|
|
||||||
#[derive(Debug, Clone)]
|
|
||||||
pub struct Param {
|
|
||||||
pub name: String,
|
|
||||||
pub type_expr: TypeExpr,
|
|
||||||
pub span: Span,
|
|
||||||
}
|
|
||||||
|
|
||||||
#[derive(Debug, Clone)]
|
|
||||||
pub struct Struct {
|
|
||||||
pub name: String,
|
|
||||||
pub fields: Vec<StructField>,
|
|
||||||
pub span: Span,
|
|
||||||
}
|
|
||||||
|
|
||||||
#[derive(Debug, Clone)]
|
|
||||||
pub struct StructField {
|
|
||||||
pub name: String,
|
|
||||||
pub type_expr: TypeExpr,
|
|
||||||
pub span: Span,
|
|
||||||
}
|
|
||||||
|
|
||||||
#[derive(Debug, Clone)]
|
|
||||||
pub struct Class {
|
|
||||||
pub name: String,
|
|
||||||
pub fields: Vec<StructField>,
|
|
||||||
pub methods: Vec<Function>,
|
|
||||||
pub span: Span,
|
|
||||||
}
|
|
||||||
|
|
||||||
#[derive(Debug, Clone)]
|
|
||||||
pub struct Import {
|
|
||||||
pub path: String,
|
|
||||||
pub span: Span,
|
|
||||||
}
|
|
||||||
|
|
||||||
#[derive(Debug, Clone)]
|
|
||||||
pub enum Statement {
|
|
||||||
Let(LetStatement),
|
|
||||||
Return(ReturnStatement),
|
|
||||||
Expression(Expression),
|
|
||||||
If(IfStatement),
|
|
||||||
For(ForStatement),
|
|
||||||
}
|
|
||||||
|
|
||||||
#[derive(Debug, Clone)]
|
|
||||||
pub struct LetStatement {
|
|
||||||
pub name: String,
|
|
||||||
pub type_expr: Option<TypeExpr>,
|
|
||||||
pub value: Expression,
|
|
||||||
pub span: Span,
|
|
||||||
}
|
|
||||||
|
|
||||||
#[derive(Debug, Clone)]
|
|
||||||
pub struct ReturnStatement {
|
|
||||||
pub value: Option<Expression>,
|
|
||||||
pub span: Span,
|
|
||||||
}
|
|
||||||
|
|
||||||
#[derive(Debug, Clone)]
|
|
||||||
pub struct IfStatement {
|
|
||||||
pub condition: Expression,
|
|
||||||
pub body: Vec<Statement>,
|
|
||||||
pub else_body: Option<Vec<Statement>>,
|
|
||||||
pub span: Span,
|
|
||||||
}
|
|
||||||
|
|
||||||
#[derive(Debug, Clone)]
|
|
||||||
pub struct ForStatement {
|
|
||||||
pub var: String,
|
|
||||||
pub iterator: Expression,
|
|
||||||
pub body: Vec<Statement>,
|
|
||||||
pub span: Span,
|
|
||||||
}
|
|
||||||
|
|
||||||
#[derive(Debug, Clone)]
|
|
||||||
pub enum Expression {
|
|
||||||
Identifier(String, Span),
|
|
||||||
Integer(i64, Span),
|
|
||||||
Float(f64, Span),
|
|
||||||
StringLit(String, Span),
|
|
||||||
Bool(bool, Span),
|
|
||||||
BinaryOp(Box<BinaryOp>),
|
|
||||||
UnaryOp(Box<UnaryOp>),
|
|
||||||
Call(Box<CallExpr>),
|
|
||||||
FieldAccess(Box<FieldAccess>),
|
|
||||||
StructInit(Box<StructInit>),
|
|
||||||
ArrayLiteral(Box<ArrayLiteral>),
|
|
||||||
}
|
|
||||||
|
|
||||||
#[derive(Debug, Clone)]
|
|
||||||
pub struct BinaryOp {
|
|
||||||
pub left: Expression,
|
|
||||||
pub op: BinOperator,
|
|
||||||
pub right: Expression,
|
|
||||||
pub span: Span,
|
|
||||||
}
|
|
||||||
|
|
||||||
#[derive(Debug, Clone)]
|
|
||||||
pub enum BinOperator {
|
|
||||||
Add,
|
|
||||||
Sub,
|
|
||||||
Mul,
|
|
||||||
Div,
|
|
||||||
Eq,
|
|
||||||
NotEq,
|
|
||||||
Lt,
|
|
||||||
Gt,
|
|
||||||
LtEq,
|
|
||||||
GtEq,
|
|
||||||
And,
|
|
||||||
Or,
|
|
||||||
}
|
|
||||||
|
|
||||||
#[derive(Debug, Clone)]
|
|
||||||
pub struct UnaryOp {
|
|
||||||
pub op: UnaryOperator,
|
|
||||||
pub expr: Expression,
|
|
||||||
pub span: Span,
|
|
||||||
}
|
|
||||||
|
|
||||||
#[derive(Debug, Clone)]
|
|
||||||
pub enum UnaryOperator {
|
|
||||||
Neg,
|
|
||||||
Not,
|
|
||||||
}
|
|
||||||
|
|
||||||
#[derive(Debug, Clone)]
|
|
||||||
pub struct CallExpr {
|
|
||||||
pub callee: Expression,
|
|
||||||
pub args: Vec<Expression>,
|
|
||||||
pub span: Span,
|
|
||||||
}
|
|
||||||
|
|
||||||
#[derive(Debug, Clone)]
|
|
||||||
pub struct FieldAccess {
|
|
||||||
pub object: Expression,
|
|
||||||
pub field: String,
|
|
||||||
pub span: Span,
|
|
||||||
}
|
|
||||||
|
|
||||||
#[derive(Debug, Clone)]
|
|
||||||
pub struct StructInit {
|
|
||||||
pub name: String,
|
|
||||||
pub fields: Vec<(String, Expression)>,
|
|
||||||
pub span: Span,
|
|
||||||
}
|
|
||||||
|
|
||||||
#[derive(Debug, Clone)]
|
|
||||||
pub enum TypeExpr {
|
pub enum TypeExpr {
|
||||||
Named(String),
|
Identifier(String),
|
||||||
Array(Box<TypeExpr>),
|
|
||||||
Optional(Box<TypeExpr>),
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug, Clone)]
|
#[derive(Debug, Clone, Serialize)]
|
||||||
pub struct ArrayLiteral {
|
pub enum BinaryOp {
|
||||||
pub elements: Vec<Expression>,
|
Plus,
|
||||||
pub span: Span,
|
Minus,
|
||||||
|
Multiply,
|
||||||
|
Divide,
|
||||||
|
Modulo,
|
||||||
|
Equal,
|
||||||
|
NotEqual,
|
||||||
|
LessThan,
|
||||||
|
GreaterThan,
|
||||||
|
LessThanOrEqual,
|
||||||
|
GreaterThanOrEqual,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Debug, Clone, Serialize)]
|
||||||
|
#[serde(tag = "type", content = "value")]
|
||||||
|
pub enum TopLevel {
|
||||||
|
Import(String),
|
||||||
|
StructDecl {
|
||||||
|
export: bool,
|
||||||
|
name: String,
|
||||||
|
fields: ParamList,
|
||||||
|
},
|
||||||
|
FunctionDecl {
|
||||||
|
export: bool,
|
||||||
|
name: String,
|
||||||
|
params: ParamList,
|
||||||
|
return_type: Option<TypeExpr>,
|
||||||
|
body: Block,
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Debug, Clone, Serialize)]
|
||||||
|
#[serde(tag = "type", content = "value")]
|
||||||
|
pub enum Postfix {
|
||||||
|
FieldAccess(String),
|
||||||
|
Call(Vec<Expression>),
|
||||||
|
Index(Expression),
|
||||||
|
Binary(BinaryOp, Expression),
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Debug, Clone, Serialize)]
|
||||||
|
#[serde(tag = "type", content = "value")]
|
||||||
|
pub enum Statement {
|
||||||
|
// expr;
|
||||||
|
Expression(Expression),
|
||||||
|
|
||||||
|
// { ... }
|
||||||
|
Block(Block),
|
||||||
|
|
||||||
|
// let/const/var x = ...
|
||||||
|
VarDecl {
|
||||||
|
kind: VarKind,
|
||||||
|
name: String,
|
||||||
|
init: Option<Expression>,
|
||||||
|
},
|
||||||
|
|
||||||
|
VarAssign {
|
||||||
|
target: Expression,
|
||||||
|
value: Expression,
|
||||||
|
},
|
||||||
|
|
||||||
|
// if (...) stmt else stmt
|
||||||
|
If {
|
||||||
|
condition: Expression,
|
||||||
|
then_branch: Box<Statement>,
|
||||||
|
else_branch: Option<Box<Statement>>,
|
||||||
|
},
|
||||||
|
|
||||||
|
// while (...) stmt
|
||||||
|
While {
|
||||||
|
condition: Expression,
|
||||||
|
body: Box<Statement>,
|
||||||
|
},
|
||||||
|
|
||||||
|
// for (...) stmt
|
||||||
|
For {
|
||||||
|
init: (VarKind, String, Option<Expression>),
|
||||||
|
condition: Option<Expression>,
|
||||||
|
update: Option<Box<Statement>>,
|
||||||
|
body: Box<Statement>,
|
||||||
|
},
|
||||||
|
|
||||||
|
// return expr?;
|
||||||
|
Return(Option<Expression>),
|
||||||
|
|
||||||
|
Break,
|
||||||
|
Continue,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Debug, Clone, Serialize)]
|
||||||
|
#[serde(tag = "type", content = "value")]
|
||||||
|
pub enum Expression {
|
||||||
|
Identifier(String),
|
||||||
|
IntLiteral(i64),
|
||||||
|
FloatLiteral(f64),
|
||||||
|
BoolLiteral(bool),
|
||||||
|
StringLiteral(String),
|
||||||
|
Postfix {
|
||||||
|
initial: Box<Expression>,
|
||||||
|
postfixes: Vec<Postfix>,
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Debug, Clone, Serialize)]
|
||||||
|
pub enum VarKind {
|
||||||
|
Let,
|
||||||
|
Const,
|
||||||
|
Var,
|
||||||
}
|
}
|
||||||
|
|||||||
+72
-117
@@ -1,8 +1,7 @@
|
|||||||
WHITESPACE = _{ " " | "\t" | "\r" | "\n" }
|
WHITESPACE = _{ " " | "\t" | "\r" | "\n" }
|
||||||
COMMENT = _{ "//" ~ (!"\n" ~ ANY)* }
|
COMMENT = _{ "//" ~ (!"\n" ~ ANY)* }
|
||||||
|
|
||||||
program = { SOI ~ item* ~ EOI }
|
program = { SOI ~ top_level* ~ EOI }
|
||||||
item = _{ import_decl | function_decl | struct_decl | class_decl }
|
|
||||||
|
|
||||||
// primitives
|
// primitives
|
||||||
identifier = @{ (ASCII_ALPHA | "_") ~ (ASCII_ALPHANUMERIC | "_")* }
|
identifier = @{ (ASCII_ALPHA | "_") ~ (ASCII_ALPHANUMERIC | "_")* }
|
||||||
@@ -12,152 +11,108 @@ boolean = { "true" | "false" }
|
|||||||
string_lit = { "\"" ~ inner_str ~ "\"" }
|
string_lit = { "\"" ~ inner_str ~ "\"" }
|
||||||
inner_str = @{ (!"\"" ~ ANY)* }
|
inner_str = @{ (!"\"" ~ ANY)* }
|
||||||
|
|
||||||
// ================= TYPE SCRIPT STYLE CHANGES =================
|
// ================= TOP LEVEL =================
|
||||||
|
|
||||||
// import becomes TS-like (still identical structure)
|
top_level = _{ import | function_decl | struct_decl }
|
||||||
import_decl = { "import" ~ string_lit ~ ";" }
|
|
||||||
|
|
||||||
// struct stays, but feels like TS "type object shape"
|
export = { "export" }
|
||||||
struct_decl = {
|
|
||||||
"struct" ~ identifier ~ "{" ~ struct_field* ~ "}"
|
|
||||||
}
|
|
||||||
|
|
||||||
// class already TS-like — just improved consistency
|
import = { "import" ~ string_lit ~ ";" }
|
||||||
class_decl = {
|
|
||||||
"class" ~ identifier ~ "{" ~ class_member* ~ "}"
|
|
||||||
}
|
|
||||||
|
|
||||||
class_member = _{ struct_field | function_decl }
|
|
||||||
|
|
||||||
// function keyword changed feel: fn → function
|
|
||||||
function_decl = {
|
|
||||||
"function" ~ identifier ~ "(" ~ param_list? ~ ")" ~ ("->" ~ type_expr)? ~ block
|
|
||||||
}
|
|
||||||
|
|
||||||
// struct fields: TS-style semicolon consistency (already good)
|
|
||||||
struct_field = { identifier ~ ":" ~ type_expr ~ ";" }
|
|
||||||
|
|
||||||
// params: TS optional typing style feel (unchanged structure)
|
|
||||||
param_list = { param ~ ("," ~ param)* ~ ","? }
|
param_list = { param ~ ("," ~ param)* ~ ","? }
|
||||||
param = { identifier ~ ":" ~ type_expr }
|
param = { identifier ~ ":" ~ type_expr }
|
||||||
|
|
||||||
|
struct_decl = {
|
||||||
|
export? ~ "struct" ~ identifier ~ "{" ~ param_list? ~ "}"
|
||||||
|
}
|
||||||
|
|
||||||
|
function_decl = {
|
||||||
|
export? ~ "function" ~ identifier ~ "(" ~ param_list? ~ ")" ~ (":" ~ type_expr)? ~ block
|
||||||
|
}
|
||||||
|
|
||||||
// ================= STATEMENTS =================
|
// ================= STATEMENTS =================
|
||||||
|
|
||||||
block = { "{" ~ statement* ~ "}" }
|
block = { "{" ~ statement_list ~ "}" }
|
||||||
|
|
||||||
|
statement_list = { statement* }
|
||||||
|
|
||||||
statement = _{
|
statement = _{
|
||||||
let_stmt
|
expr_stmt
|
||||||
| return_stmt
|
| var_decl
|
||||||
|
| var_assign
|
||||||
| if_stmt
|
| if_stmt
|
||||||
|
| while_stmt
|
||||||
| for_stmt
|
| for_stmt
|
||||||
| assign_stmt
|
| return_stmt
|
||||||
| expression_stmt
|
| break_stmt
|
||||||
|
| continue_stmt
|
||||||
|
| block
|
||||||
}
|
}
|
||||||
|
|
||||||
// expression statements: TS allows no semicolon in real life,
|
// --- basic statements ---
|
||||||
// but we keep your structure
|
|
||||||
expression_stmt = { expression ~ ";" }
|
|
||||||
|
|
||||||
// assignment unchanged (JS/TS feel already)
|
expr_stmt = { expr ~ ";" }
|
||||||
assign_stmt = { identifier ~ "=" ~ expression ~ ";" }
|
|
||||||
|
|
||||||
// let → const/let feel (still your rule, just TS naming)
|
return_stmt = { "return" ~ expr? ~ ";" }
|
||||||
let_stmt = {
|
|
||||||
"const" ~ identifier ~ (":" ~ type_expr)? ~ "=" ~ expression ~ ";"
|
break_stmt = { "break" ~ ";" }
|
||||||
|
|
||||||
|
continue_stmt = { "continue" ~ ";" }
|
||||||
|
|
||||||
|
// --- variable declarations ---
|
||||||
|
|
||||||
|
var_decl_kind = { "let" | "const" | "var" }
|
||||||
|
|
||||||
|
var_decl = {
|
||||||
|
var_decl_kind ~ identifier ~ ("=" ~ expr)? ~ ";"
|
||||||
}
|
}
|
||||||
|
|
||||||
// return: TS-like (no change except feel consistency)
|
var_assign = {
|
||||||
return_stmt = { "return" ~ expression? ~ ";" }
|
expr ~ "=" ~ expr ~ ";"
|
||||||
|
}
|
||||||
|
|
||||||
|
// --- control flow ---
|
||||||
|
|
||||||
// if: add TS-style parentheses (MAJOR feel upgrade, same structure)
|
|
||||||
if_stmt = {
|
if_stmt = {
|
||||||
"if" ~ "(" ~ expression ~ ")" ~ block ~ ("else" ~ block)?
|
"if" ~ "(" ~ expr ~ ")" ~ statement ~ ("else" ~ statement)?
|
||||||
|
}
|
||||||
|
|
||||||
|
while_stmt = {
|
||||||
|
"while" ~ "(" ~ expr ~ ")" ~ statement
|
||||||
}
|
}
|
||||||
|
|
||||||
// for: TS-like "of"
|
|
||||||
for_stmt = {
|
for_stmt = {
|
||||||
"for" ~ identifier ~ "of" ~ expression ~ block
|
"for" ~ "(" ~ var_decl ~ expr ~ ";" ~ var_assign_no_semicolon ~ ")" ~ statement
|
||||||
}
|
}
|
||||||
|
|
||||||
// ================= TYPES (KEEP STRUCTURE, TS FEEL) =================
|
var_assign_no_semicolon = {
|
||||||
|
expr ~ "=" ~ expr
|
||||||
type_expr = { base_type ~ "?"? }
|
}
|
||||||
base_type = _{ array_type | identifier }
|
|
||||||
array_type = { "[" ~ type_expr ~ "]" }
|
|
||||||
|
|
||||||
// ================= EXPRESSIONS =================
|
// ================= EXPRESSIONS =================
|
||||||
|
type_expr = { identifier }
|
||||||
|
|
||||||
expression = { term ~ (bin_op ~ term)* }
|
primary = {
|
||||||
|
integer
|
||||||
bin_op = _{
|
|
||||||
eq
|
|
||||||
| neq
|
|
||||||
| lte
|
|
||||||
| gte
|
|
||||||
| lt
|
|
||||||
| gt
|
|
||||||
| and
|
|
||||||
| or
|
|
||||||
| add
|
|
||||||
| sub
|
|
||||||
| mul
|
|
||||||
| div
|
|
||||||
}
|
|
||||||
|
|
||||||
add = { "+" }
|
|
||||||
sub = { "-" }
|
|
||||||
mul = { "*" }
|
|
||||||
div = { "/" }
|
|
||||||
eq = { "==" }
|
|
||||||
neq = { "!=" }
|
|
||||||
lte = { "<=" }
|
|
||||||
gte = { ">=" }
|
|
||||||
lt = { "<" }
|
|
||||||
gt = { ">" }
|
|
||||||
and = { "&&" }
|
|
||||||
or = { "||" }
|
|
||||||
|
|
||||||
// ================= LITERALS =================
|
|
||||||
|
|
||||||
struct_literal = {
|
|
||||||
identifier ~ "{" ~ struct_init_list? ~ "}"
|
|
||||||
}
|
|
||||||
|
|
||||||
struct_init_list = {
|
|
||||||
struct_init_field ~ ("," ~ struct_init_field)* ~ ","?
|
|
||||||
}
|
|
||||||
|
|
||||||
struct_init_field = {
|
|
||||||
identifier ~ ":" ~ expression
|
|
||||||
}
|
|
||||||
|
|
||||||
array_literal = {
|
|
||||||
"[" ~ (expression ~ ("," ~ expression)*)? ~ ","? ~ "]"
|
|
||||||
}
|
|
||||||
|
|
||||||
// ================= CHAINING =================
|
|
||||||
|
|
||||||
term = { primary ~ (field_access | call_suffix)* }
|
|
||||||
|
|
||||||
field_access = { "." ~ identifier }
|
|
||||||
|
|
||||||
call_suffix = {
|
|
||||||
"(" ~ (expression ~ ("," ~ expression)*)? ~ ","? ~ ")"
|
|
||||||
}
|
|
||||||
|
|
||||||
// ================= PRIMARY =================
|
|
||||||
|
|
||||||
primary = _{
|
|
||||||
struct_literal
|
|
||||||
| array_literal
|
|
||||||
| float
|
| float
|
||||||
| integer
|
|
||||||
| string_lit
|
|
||||||
| boolean
|
| boolean
|
||||||
| self_kw
|
| string_lit
|
||||||
| null_kw
|
|
||||||
| identifier
|
| identifier
|
||||||
}
|
}
|
||||||
|
|
||||||
self_kw = { "this" }
|
postfix = {
|
||||||
null_kw = { "null" }
|
field_px
|
||||||
|
| call_px
|
||||||
|
| index_px
|
||||||
|
| binary_px
|
||||||
|
}
|
||||||
|
|
||||||
|
field_px = { "." ~ identifier }
|
||||||
|
call_px = { "(" ~ (expr ~ ("," ~ expr)*)? ~ ")" }
|
||||||
|
index_px = { "[" ~ expr ~ "]" }
|
||||||
|
binary_px = { bin_op ~ expr }
|
||||||
|
bin_op = { "+" | "-" | "*" | "/" | "%" | "==" | "!=" | "<" | ">" | "<=" | ">=" }
|
||||||
|
|
||||||
|
expr = {
|
||||||
|
primary ~ postfix*
|
||||||
|
}
|
||||||
|
|||||||
+342
-325
@@ -1,5 +1,4 @@
|
|||||||
use pest::Parser;
|
use pest::Parser;
|
||||||
use pest::iterators::Pair;
|
|
||||||
use pest_derive::Parser;
|
use pest_derive::Parser;
|
||||||
|
|
||||||
pub mod ast;
|
pub mod ast;
|
||||||
@@ -12,352 +11,370 @@ pub struct MistParser;
|
|||||||
// convenience alias for pest errors
|
// convenience alias for pest errors
|
||||||
pub type ParseError = pest::error::Error<Rule>;
|
pub type ParseError = pest::error::Error<Rule>;
|
||||||
|
|
||||||
pub fn parse(source: &str) -> Result<Program, ParseError> {
|
pub fn parse(source: &str) -> Result<Vec<TopLevel>, ParseError> {
|
||||||
let pairs = MistParser::parse(Rule::program, source)?;
|
let mut pairs = MistParser::parse(Rule::program, source)?;
|
||||||
|
|
||||||
let mut statements = vec![];
|
let mut statements = vec![];
|
||||||
|
|
||||||
// pairs is an iterator over the top-level program pair
|
for pair in pairs.next().unwrap().into_inner() {
|
||||||
// we need to get its inner children
|
if let Some(stmt) = TopLevel::from_pair(pair) {
|
||||||
for pair in pairs {
|
statements.push(stmt);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Ok(statements)
|
||||||
|
}
|
||||||
|
|
||||||
|
impl TypeExpr {
|
||||||
|
pub fn from_pair(pair: pest::iterators::Pair<Rule>) -> Self {
|
||||||
match pair.as_rule() {
|
match pair.as_rule() {
|
||||||
Rule::program => {
|
Rule::type_expr => {
|
||||||
for inner in pair.into_inner() {
|
let inner = pair.into_inner().next().unwrap();
|
||||||
match inner.as_rule() {
|
TypeExpr::from_pair(inner)
|
||||||
Rule::function_decl => {
|
}
|
||||||
statements.push(TopLevel::Function(parse_function(inner)))
|
Rule::identifier => TypeExpr::Identifier(pair.as_str().to_string()),
|
||||||
}
|
_ => unimplemented!("TypeExpr parsing not implemented yet"),
|
||||||
Rule::struct_decl => statements.push(TopLevel::Struct(parse_struct(inner))),
|
}
|
||||||
Rule::class_decl => statements.push(TopLevel::Class(parse_class(inner))),
|
}
|
||||||
Rule::import_decl => statements.push(TopLevel::Import(parse_import(inner))),
|
}
|
||||||
Rule::EOI => {}
|
|
||||||
_ => {}
|
impl ParamList {
|
||||||
|
pub fn from_pair(pair: pest::iterators::Pair<Rule>) -> Self {
|
||||||
|
let params = pair
|
||||||
|
.into_inner()
|
||||||
|
.map(|p| {
|
||||||
|
let mut param_inner = p.into_inner();
|
||||||
|
let param_name = param_inner.next().unwrap().as_str().to_string();
|
||||||
|
let param_type = TypeExpr::from_pair(param_inner.next().unwrap());
|
||||||
|
(param_name, param_type)
|
||||||
|
})
|
||||||
|
.collect();
|
||||||
|
|
||||||
|
ParamList(params)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl TopLevel {
|
||||||
|
pub fn from_pair(pair: pest::iterators::Pair<Rule>) -> Option<Self> {
|
||||||
|
match pair.as_rule() {
|
||||||
|
Rule::import => {
|
||||||
|
let path = pair.into_inner().next().unwrap().as_str().to_string();
|
||||||
|
Some(TopLevel::Import(path))
|
||||||
|
}
|
||||||
|
Rule::function_decl => {
|
||||||
|
let mut inner = pair.into_inner();
|
||||||
|
|
||||||
|
let export = if let Some(first) = inner.peek() {
|
||||||
|
if first.as_rule() == Rule::export {
|
||||||
|
inner.next();
|
||||||
|
true
|
||||||
|
} else {
|
||||||
|
false
|
||||||
}
|
}
|
||||||
|
} else {
|
||||||
|
false
|
||||||
|
};
|
||||||
|
let name = inner.next().unwrap().as_str().to_string();
|
||||||
|
let params_pair = inner.next().unwrap();
|
||||||
|
let params = if params_pair.as_rule() == Rule::param_list {
|
||||||
|
ParamList::from_pair(params_pair)
|
||||||
|
} else {
|
||||||
|
ParamList(vec![])
|
||||||
|
};
|
||||||
|
let return_type = if let Some(next) = inner.peek() {
|
||||||
|
if next.as_rule() == Rule::type_expr {
|
||||||
|
Some(TypeExpr::from_pair(inner.next().unwrap()))
|
||||||
|
} else {
|
||||||
|
None
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
None
|
||||||
|
};
|
||||||
|
|
||||||
|
let body = Block::from_pair(inner.next().unwrap());
|
||||||
|
|
||||||
|
Some(TopLevel::FunctionDecl {
|
||||||
|
export,
|
||||||
|
name,
|
||||||
|
params,
|
||||||
|
return_type,
|
||||||
|
body,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
Rule::struct_decl => {
|
||||||
|
let mut inner = pair.into_inner();
|
||||||
|
let export = if let Some(first) = inner.peek() {
|
||||||
|
if first.as_rule() == Rule::export {
|
||||||
|
inner.next();
|
||||||
|
true
|
||||||
|
} else {
|
||||||
|
false
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
false
|
||||||
|
};
|
||||||
|
let name = inner.next().unwrap().as_str().to_string();
|
||||||
|
let fields_pair = inner.next().unwrap();
|
||||||
|
let fields = ParamList::from_pair(fields_pair);
|
||||||
|
|
||||||
|
Some(TopLevel::StructDecl {
|
||||||
|
export,
|
||||||
|
name,
|
||||||
|
fields,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
Rule::EOI => None,
|
||||||
|
_ => unimplemented!("TopLevel parsing not implemented yet {:?}", pair.as_rule()),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Block {
|
||||||
|
pub fn from_pair(pair: pest::iterators::Pair<Rule>) -> Self {
|
||||||
|
let statements = pair
|
||||||
|
.into_inner()
|
||||||
|
.flat_map(|pair| {
|
||||||
|
if pair.as_rule() == Rule::statement_list {
|
||||||
|
pair.into_inner().map(Statement::from_pair).collect()
|
||||||
|
} else {
|
||||||
|
vec![Statement::from_pair(pair)]
|
||||||
}
|
}
|
||||||
|
})
|
||||||
|
.collect();
|
||||||
|
Block(statements)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Statement {
|
||||||
|
pub fn from_pair(pair: pest::iterators::Pair<Rule>) -> Self {
|
||||||
|
match pair.as_rule() {
|
||||||
|
Rule::statement => {
|
||||||
|
let inner = pair.into_inner().next().unwrap();
|
||||||
|
Statement::from_pair(inner)
|
||||||
}
|
}
|
||||||
Rule::EOI => {}
|
|
||||||
_ => {}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
Ok(Program { statements })
|
Rule::expr_stmt => {
|
||||||
}
|
let expr_pair = pair.into_inner().next().unwrap();
|
||||||
|
Statement::Expression(Expression::from_pair(expr_pair))
|
||||||
fn span_of(pair: &Pair<Rule>) -> Span {
|
|
||||||
let s = pair.as_span();
|
|
||||||
Span {
|
|
||||||
start: s.start(),
|
|
||||||
end: s.end(),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fn parse_function(pair: Pair<Rule>) -> Function {
|
|
||||||
let span = span_of(&pair);
|
|
||||||
let mut inner = pair.into_inner();
|
|
||||||
|
|
||||||
let name = inner.next().unwrap().as_str().to_string();
|
|
||||||
|
|
||||||
let mut params = vec![];
|
|
||||||
let mut return_type = None;
|
|
||||||
let mut body = vec![];
|
|
||||||
|
|
||||||
for part in inner {
|
|
||||||
match part.as_rule() {
|
|
||||||
Rule::param_list => params = parse_param_list(part),
|
|
||||||
Rule::type_expr => return_type = Some(parse_type_expr(part)),
|
|
||||||
Rule::block => body = parse_block(part),
|
|
||||||
_ => {}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
Function {
|
|
||||||
name,
|
|
||||||
params,
|
|
||||||
return_type,
|
|
||||||
body,
|
|
||||||
span,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fn parse_param_list(pair: Pair<Rule>) -> Vec<Param> {
|
|
||||||
pair.into_inner()
|
|
||||||
.map(|p| {
|
|
||||||
let span = span_of(&p);
|
|
||||||
let mut inner = p.into_inner();
|
|
||||||
let name = inner.next().unwrap().as_str().to_string();
|
|
||||||
let type_expr = parse_type_expr(inner.next().unwrap());
|
|
||||||
Param {
|
|
||||||
name,
|
|
||||||
type_expr,
|
|
||||||
span,
|
|
||||||
}
|
}
|
||||||
})
|
|
||||||
.collect()
|
|
||||||
}
|
|
||||||
|
|
||||||
fn parse_struct(pair: Pair<Rule>) -> Struct {
|
Rule::block => Statement::Block(Block::from_pair(pair.into_inner().next().unwrap())),
|
||||||
let span = span_of(&pair);
|
|
||||||
let mut inner = pair.into_inner();
|
|
||||||
let name = inner.next().unwrap().as_str().to_string();
|
|
||||||
let fields = inner.map(|f| parse_struct_field(f)).collect();
|
|
||||||
Struct { name, fields, span }
|
|
||||||
}
|
|
||||||
|
|
||||||
fn parse_struct_field(pair: Pair<Rule>) -> StructField {
|
Rule::var_decl => {
|
||||||
let span = span_of(&pair);
|
let mut inner = pair.into_inner();
|
||||||
let mut inner = pair.into_inner();
|
|
||||||
let name = inner.next().unwrap().as_str().to_string();
|
|
||||||
let type_expr = parse_type_expr(inner.next().unwrap());
|
|
||||||
StructField {
|
|
||||||
name,
|
|
||||||
type_expr,
|
|
||||||
span,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fn parse_class(pair: Pair<Rule>) -> Class {
|
let kind_pair = inner.next().unwrap(); // let/const/var
|
||||||
let span = span_of(&pair);
|
let name_pair = inner.next().unwrap(); // identifier
|
||||||
let mut inner = pair.into_inner();
|
|
||||||
let name = inner.next().unwrap().as_str().to_string();
|
|
||||||
let mut fields = vec![];
|
|
||||||
let mut methods = vec![];
|
|
||||||
|
|
||||||
for part in inner {
|
let init = inner.next().map(|expr_pair| {
|
||||||
match part.as_rule() {
|
// expects "=" expr
|
||||||
Rule::struct_field => fields.push(parse_struct_field(part)),
|
Expression::from_pair(expr_pair.into_inner().next().unwrap())
|
||||||
Rule::function_decl => methods.push(parse_function(part)),
|
});
|
||||||
_ => {}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
Class {
|
let kind = match kind_pair.as_str() {
|
||||||
name,
|
"let" => VarKind::Let,
|
||||||
fields,
|
"const" => VarKind::Const,
|
||||||
methods,
|
"var" => VarKind::Var,
|
||||||
span,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fn parse_import(pair: Pair<Rule>) -> Import {
|
|
||||||
let span = span_of(&pair);
|
|
||||||
let path = pair.into_inner().next().unwrap().as_str().to_string();
|
|
||||||
Import { path, span }
|
|
||||||
}
|
|
||||||
|
|
||||||
fn parse_block(pair: Pair<Rule>) -> Vec<Statement> {
|
|
||||||
pair.into_inner()
|
|
||||||
.filter_map(|p| parse_statement(p))
|
|
||||||
.collect()
|
|
||||||
}
|
|
||||||
|
|
||||||
fn parse_statement(pair: Pair<Rule>) -> Option<Statement> {
|
|
||||||
match pair.as_rule() {
|
|
||||||
Rule::let_stmt => Some(Statement::Let(parse_let(pair))),
|
|
||||||
Rule::return_stmt => Some(Statement::Return(parse_return(pair))),
|
|
||||||
Rule::if_stmt => Some(Statement::If(parse_if(pair))),
|
|
||||||
Rule::for_stmt => Some(Statement::For(parse_for(pair))),
|
|
||||||
Rule::expression_stmt => {
|
|
||||||
let expr = pair.into_inner().next().unwrap();
|
|
||||||
Some(Statement::Expression(parse_expression(expr)))
|
|
||||||
}
|
|
||||||
Rule::expression => Some(Statement::Expression(parse_expression(pair))),
|
|
||||||
_ => None,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fn parse_let(pair: Pair<Rule>) -> LetStatement {
|
|
||||||
let span = span_of(&pair);
|
|
||||||
let mut inner = pair.into_inner();
|
|
||||||
let name = inner.next().unwrap().as_str().to_string();
|
|
||||||
|
|
||||||
// peek ahead — next is either a type or an expression
|
|
||||||
let next = inner.next().unwrap();
|
|
||||||
let (type_expr, value) = if next.as_rule() == Rule::type_expr {
|
|
||||||
(
|
|
||||||
Some(parse_type_expr(next)),
|
|
||||||
parse_expression(inner.next().unwrap()),
|
|
||||||
)
|
|
||||||
} else {
|
|
||||||
(None, parse_expression(next))
|
|
||||||
};
|
|
||||||
|
|
||||||
LetStatement {
|
|
||||||
name,
|
|
||||||
type_expr,
|
|
||||||
value,
|
|
||||||
span,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fn parse_return(pair: Pair<Rule>) -> ReturnStatement {
|
|
||||||
let span = span_of(&pair);
|
|
||||||
let value = pair.into_inner().next().map(|p| parse_expression(p));
|
|
||||||
ReturnStatement { value, span }
|
|
||||||
}
|
|
||||||
|
|
||||||
fn parse_if(pair: Pair<Rule>) -> IfStatement {
|
|
||||||
let span = span_of(&pair);
|
|
||||||
let mut inner = pair.into_inner();
|
|
||||||
let condition = parse_expression(inner.next().unwrap());
|
|
||||||
let body = parse_block(inner.next().unwrap());
|
|
||||||
let else_body = inner.next().map(|p| parse_block(p));
|
|
||||||
IfStatement {
|
|
||||||
condition,
|
|
||||||
body,
|
|
||||||
else_body,
|
|
||||||
span,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fn parse_for(pair: Pair<Rule>) -> ForStatement {
|
|
||||||
let span = span_of(&pair);
|
|
||||||
let mut inner = pair.into_inner();
|
|
||||||
let var = inner.next().unwrap().as_str().to_string();
|
|
||||||
let iterator = parse_expression(inner.next().unwrap());
|
|
||||||
let body = parse_block(inner.next().unwrap());
|
|
||||||
ForStatement {
|
|
||||||
var,
|
|
||||||
iterator,
|
|
||||||
body,
|
|
||||||
span,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fn parse_expression(pair: Pair<Rule>) -> Expression {
|
|
||||||
match pair.as_rule() {
|
|
||||||
Rule::expression => {
|
|
||||||
let mut inner = pair.into_inner();
|
|
||||||
let mut expr = parse_term(inner.next().unwrap());
|
|
||||||
|
|
||||||
// consume pairs of (bin_op, term)
|
|
||||||
while let Some(op_pair) = inner.next() {
|
|
||||||
let right = parse_term(inner.next().unwrap());
|
|
||||||
let span = span_of(&op_pair);
|
|
||||||
let op = match op_pair.as_rule() {
|
|
||||||
Rule::add => BinOperator::Add,
|
|
||||||
Rule::sub => BinOperator::Sub,
|
|
||||||
Rule::mul => BinOperator::Mul,
|
|
||||||
Rule::div => BinOperator::Div,
|
|
||||||
Rule::eq => BinOperator::Eq,
|
|
||||||
Rule::neq => BinOperator::NotEq,
|
|
||||||
Rule::lt => BinOperator::Lt,
|
|
||||||
Rule::gt => BinOperator::Gt,
|
|
||||||
Rule::lte => BinOperator::LtEq,
|
|
||||||
Rule::gte => BinOperator::GtEq,
|
|
||||||
Rule::and => BinOperator::And,
|
|
||||||
Rule::or => BinOperator::Or,
|
|
||||||
_ => unreachable!(),
|
_ => unreachable!(),
|
||||||
};
|
};
|
||||||
expr = Expression::BinaryOp(Box::new(BinaryOp {
|
|
||||||
left: expr,
|
Statement::VarDecl {
|
||||||
op,
|
kind,
|
||||||
right,
|
name: name_pair.as_str().to_string(),
|
||||||
span,
|
init,
|
||||||
}));
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
expr
|
Rule::return_stmt => {
|
||||||
|
let mut inner = pair.into_inner();
|
||||||
|
|
||||||
|
let expr = inner.next().map(Expression::from_pair);
|
||||||
|
|
||||||
|
Statement::Return(expr)
|
||||||
|
}
|
||||||
|
|
||||||
|
Rule::break_stmt => Statement::Break,
|
||||||
|
|
||||||
|
Rule::continue_stmt => Statement::Continue,
|
||||||
|
|
||||||
|
Rule::if_stmt => {
|
||||||
|
let mut inner = pair.into_inner();
|
||||||
|
|
||||||
|
let condition = Expression::from_pair(inner.next().unwrap());
|
||||||
|
let then_branch = Statement::from_pair(inner.next().unwrap());
|
||||||
|
|
||||||
|
let else_branch = inner.next().map(Statement::from_pair);
|
||||||
|
|
||||||
|
Statement::If {
|
||||||
|
condition,
|
||||||
|
then_branch: Box::new(then_branch),
|
||||||
|
else_branch: else_branch.map(Box::new),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Rule::while_stmt => {
|
||||||
|
let mut inner = pair.into_inner();
|
||||||
|
|
||||||
|
let condition = Expression::from_pair(inner.next().unwrap());
|
||||||
|
let body = Statement::from_pair(inner.next().unwrap());
|
||||||
|
|
||||||
|
Statement::While {
|
||||||
|
condition,
|
||||||
|
body: Box::new(body),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Rule::for_stmt => {
|
||||||
|
let mut inner = pair.into_inner();
|
||||||
|
|
||||||
|
let init = inner
|
||||||
|
.next()
|
||||||
|
.map(|p| match p.as_rule() {
|
||||||
|
Rule::var_decl => {
|
||||||
|
let mut it = p.into_inner();
|
||||||
|
|
||||||
|
let kind = match it.next().unwrap().as_str() {
|
||||||
|
"let" => VarKind::Let,
|
||||||
|
"const" => VarKind::Const,
|
||||||
|
"var" => VarKind::Var,
|
||||||
|
_ => unreachable!(),
|
||||||
|
};
|
||||||
|
|
||||||
|
let name = it.next().unwrap().as_str().to_string();
|
||||||
|
let init_expr = it
|
||||||
|
.next()
|
||||||
|
.map(|e| Expression::from_pair(e.into_inner().next().unwrap()));
|
||||||
|
|
||||||
|
(kind, name, init_expr)
|
||||||
|
}
|
||||||
|
_ => unimplemented!(
|
||||||
|
"For loop init parsing not implemented yet: {:?}",
|
||||||
|
p.as_rule()
|
||||||
|
),
|
||||||
|
})
|
||||||
|
.unwrap();
|
||||||
|
|
||||||
|
let condition = inner.next().map(Expression::from_pair);
|
||||||
|
let update = inner.next().map(parse_var_assign_no_semicolon);
|
||||||
|
let body = Statement::from_pair(inner.next().unwrap());
|
||||||
|
|
||||||
|
Statement::For {
|
||||||
|
init,
|
||||||
|
condition,
|
||||||
|
update: update.map(Box::new),
|
||||||
|
body: Box::new(body),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Rule::var_assign => {
|
||||||
|
let mut inner = pair.into_inner();
|
||||||
|
let target = Expression::from_pair(inner.next().unwrap());
|
||||||
|
let value = Expression::from_pair(inner.next().unwrap());
|
||||||
|
|
||||||
|
Statement::VarAssign { target, value }
|
||||||
|
}
|
||||||
|
|
||||||
|
_ => unimplemented!(
|
||||||
|
"Statement parsing not implemented yet: {:?}",
|
||||||
|
pair.as_rule()
|
||||||
|
),
|
||||||
}
|
}
|
||||||
_ => parse_term(pair),
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn parse_term(pair: Pair<Rule>) -> Expression {
|
impl Expression {
|
||||||
|
pub fn from_pair(pair: pest::iterators::Pair<Rule>) -> Self {
|
||||||
|
match pair.as_rule() {
|
||||||
|
Rule::expr => {
|
||||||
|
let mut inner = pair.into_inner();
|
||||||
|
let exp = Expression::from_pair(inner.next().unwrap());
|
||||||
|
|
||||||
|
if inner.len() > 0 {
|
||||||
|
Expression::Postfix {
|
||||||
|
initial: Box::new(exp),
|
||||||
|
postfixes: inner.map(|p| Postfix::from_pair(p)).collect(),
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
exp
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Rule::primary => Expression::from_pair(pair.into_inner().next().unwrap()),
|
||||||
|
Rule::identifier => Expression::Identifier(pair.as_str().to_string()),
|
||||||
|
Rule::integer => {
|
||||||
|
let value = pair.as_str().parse::<i64>().unwrap();
|
||||||
|
Expression::IntLiteral(value)
|
||||||
|
}
|
||||||
|
Rule::float => {
|
||||||
|
let value = pair.as_str().parse::<f64>().unwrap();
|
||||||
|
Expression::FloatLiteral(value)
|
||||||
|
}
|
||||||
|
Rule::boolean => {
|
||||||
|
let value = pair.as_str().parse::<bool>().unwrap();
|
||||||
|
Expression::BoolLiteral(value)
|
||||||
|
}
|
||||||
|
Rule::string_lit => {
|
||||||
|
let inner_str = pair.into_inner().next().unwrap().as_str();
|
||||||
|
Expression::StringLiteral(inner_str.to_string())
|
||||||
|
}
|
||||||
|
|
||||||
|
_ => unimplemented!(
|
||||||
|
"Expression parsing not implemented yet {:?}",
|
||||||
|
pair.as_rule()
|
||||||
|
),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Postfix {
|
||||||
|
pub fn from_pair(pair: pest::iterators::Pair<Rule>) -> Self {
|
||||||
|
match pair.as_rule() {
|
||||||
|
Rule::postfix => Postfix::from_pair(pair.into_inner().next().unwrap()),
|
||||||
|
|
||||||
|
Rule::field_px => {
|
||||||
|
let field_name = pair.into_inner().next().unwrap().as_str().to_string();
|
||||||
|
Postfix::FieldAccess(field_name)
|
||||||
|
}
|
||||||
|
|
||||||
|
Rule::call_px => Postfix::Call(pair.into_inner().map(Expression::from_pair).collect()),
|
||||||
|
|
||||||
|
Rule::index_px => {
|
||||||
|
Postfix::Index(Expression::from_pair(pair.into_inner().next().unwrap()))
|
||||||
|
}
|
||||||
|
|
||||||
|
Rule::binary_px => {
|
||||||
|
let mut inner = pair.into_inner();
|
||||||
|
let op_pair = inner.next().unwrap();
|
||||||
|
let op = match op_pair.as_str() {
|
||||||
|
"+" => BinaryOp::Plus,
|
||||||
|
"-" => BinaryOp::Minus,
|
||||||
|
"*" => BinaryOp::Multiply,
|
||||||
|
"/" => BinaryOp::Divide,
|
||||||
|
"%" => BinaryOp::Modulo,
|
||||||
|
"==" => BinaryOp::Equal,
|
||||||
|
"!=" => BinaryOp::NotEqual,
|
||||||
|
"<" => BinaryOp::LessThan,
|
||||||
|
">" => BinaryOp::GreaterThan,
|
||||||
|
"<=" => BinaryOp::LessThanOrEqual,
|
||||||
|
">=" => BinaryOp::GreaterThanOrEqual,
|
||||||
|
|
||||||
|
_ => {
|
||||||
|
unimplemented!("Binary operator not implemented yet: {}", op_pair.as_str())
|
||||||
|
}
|
||||||
|
};
|
||||||
|
Postfix::Binary(op, Expression::from_pair(inner.next().unwrap()))
|
||||||
|
}
|
||||||
|
|
||||||
|
_ => unimplemented!("Postfix parsing not implemented yet {:?}", pair.as_rule()),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn parse_var_assign_no_semicolon(pair: pest::iterators::Pair<Rule>) -> Statement {
|
||||||
let mut inner = pair.into_inner();
|
let mut inner = pair.into_inner();
|
||||||
let mut expr = parse_primary(inner.next().unwrap());
|
let target = Expression::from_pair(inner.next().unwrap());
|
||||||
|
let value = Expression::from_pair(inner.next().unwrap());
|
||||||
|
|
||||||
for part in inner {
|
Statement::VarAssign { target, value }
|
||||||
let span = span_of(&part);
|
|
||||||
match part.as_rule() {
|
|
||||||
Rule::field_access => {
|
|
||||||
let field = part.into_inner().next().unwrap().as_str().to_string();
|
|
||||||
expr = Expression::FieldAccess(Box::new(FieldAccess {
|
|
||||||
object: expr,
|
|
||||||
field,
|
|
||||||
span,
|
|
||||||
}));
|
|
||||||
}
|
|
||||||
Rule::call_suffix => {
|
|
||||||
let args = part.into_inner().map(|p| parse_expression(p)).collect();
|
|
||||||
expr = Expression::Call(Box::new(CallExpr {
|
|
||||||
callee: expr,
|
|
||||||
args,
|
|
||||||
span,
|
|
||||||
}));
|
|
||||||
}
|
|
||||||
_ => {}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
expr
|
|
||||||
}
|
|
||||||
|
|
||||||
fn parse_primary(pair: Pair<Rule>) -> Expression {
|
|
||||||
let span = span_of(&pair);
|
|
||||||
|
|
||||||
match pair.as_rule() {
|
|
||||||
Rule::struct_literal => {
|
|
||||||
let mut inner = pair.into_inner();
|
|
||||||
let name = inner.next().unwrap().as_str().to_string();
|
|
||||||
|
|
||||||
inner = inner.next().unwrap().into_inner();
|
|
||||||
|
|
||||||
// println!("{inner:#?}");
|
|
||||||
|
|
||||||
let mut fields = vec![];
|
|
||||||
for field in inner {
|
|
||||||
let mut f_inner = field.into_inner();
|
|
||||||
let field_name = f_inner.next().unwrap().as_str().to_string();
|
|
||||||
let value = parse_expression(f_inner.next().unwrap());
|
|
||||||
|
|
||||||
fields.push((field_name, value));
|
|
||||||
}
|
|
||||||
|
|
||||||
Expression::StructInit(Box::new(StructInit { name, fields, span }))
|
|
||||||
}
|
|
||||||
|
|
||||||
Rule::array_literal => {
|
|
||||||
let elements = pair.into_inner().map(|p| parse_expression(p)).collect();
|
|
||||||
|
|
||||||
Expression::ArrayLiteral(Box::new(ArrayLiteral { elements, span }))
|
|
||||||
}
|
|
||||||
|
|
||||||
Rule::integer => Expression::Integer(pair.as_str().parse().unwrap(), span),
|
|
||||||
Rule::float => Expression::Float(pair.as_str().parse().unwrap(), span),
|
|
||||||
|
|
||||||
Rule::string_lit => {
|
|
||||||
Expression::StringLit(pair.into_inner().next().unwrap().as_str().to_string(), span)
|
|
||||||
}
|
|
||||||
|
|
||||||
Rule::boolean => Expression::Bool(pair.as_str() == "true", span),
|
|
||||||
|
|
||||||
Rule::self_kw => Expression::Identifier("self".to_string(), span),
|
|
||||||
Rule::null_kw => Expression::Identifier("null".to_string(), span),
|
|
||||||
Rule::identifier => Expression::Identifier(pair.as_str().to_string(), span),
|
|
||||||
|
|
||||||
Rule::term => parse_term(pair),
|
|
||||||
|
|
||||||
_ => unreachable!("unexpected primary rule: {:?}", pair.as_rule()),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fn parse_type_expr(pair: Pair<Rule>) -> TypeExpr {
|
|
||||||
let mut inner = pair.into_inner();
|
|
||||||
let base = inner.next().unwrap();
|
|
||||||
|
|
||||||
let base_type = match base.as_rule() {
|
|
||||||
Rule::array_type => {
|
|
||||||
let inner_type = parse_type_expr(base.into_inner().next().unwrap());
|
|
||||||
TypeExpr::Array(Box::new(inner_type))
|
|
||||||
}
|
|
||||||
Rule::identifier => TypeExpr::Named(base.as_str().to_string()),
|
|
||||||
_ => unreachable!(),
|
|
||||||
};
|
|
||||||
|
|
||||||
// if a "?" suffix was present, wrap in Optional
|
|
||||||
if inner.next().is_some() {
|
|
||||||
TypeExpr::Optional(Box::new(base_type))
|
|
||||||
} else {
|
|
||||||
base_type
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|||||||
+14
-6
@@ -1,9 +1,17 @@
|
|||||||
import "fmt";
|
function add(a: int, b: int): int {
|
||||||
|
let sum = 0;
|
||||||
|
|
||||||
function add(a: int, b: int) -> int {
|
for (let i = 0; i < 10; i = i + 1) {
|
||||||
return a + b;
|
if (i == 5) {
|
||||||
}
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
function main() {
|
sum = sum + i;
|
||||||
fmt.Println(add(10, 10) / 2);
|
}
|
||||||
|
|
||||||
|
if (sum > 20) {
|
||||||
|
return sum;
|
||||||
|
} else {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
Reference in New Issue
Block a user