991 lines
No EOL
44 KiB
Rust
991 lines
No EOL
44 KiB
Rust
use crate::{lexer::{Token, TokenType}, Context};
|
|
use std::process;
|
|
use crate::errors::{create_error, print_error, ErrorSubType, ErrorType};
|
|
|
|
#[derive(Debug, Clone, PartialEq)]
|
|
pub enum ASTPart {
|
|
String(AstString),
|
|
Number(AstNumber),
|
|
Boolean(AstBool),
|
|
Null(AstNull),
|
|
Assigment(AstAssigment),
|
|
Operation(AstOperation),
|
|
VarRead(AstVarRead),
|
|
Call(AstCall),
|
|
VarUpdate(AstVarUpdate),
|
|
Function(AstFunction),
|
|
If(AstIf),
|
|
ElseIf(AstElseIf),
|
|
Else(AstElse),
|
|
While(AstWhile),
|
|
Break(AstBreak),
|
|
For(AstFor),
|
|
Continue(AstContinue),
|
|
Return(AstReturn),
|
|
Table(AstTable),
|
|
TableGet(AstTableGet),
|
|
TableSet(AstTableSet),
|
|
Import(AstImport),
|
|
TryCatch(AstTryCatch),
|
|
NOOP
|
|
}
|
|
#[derive(Debug, Clone, PartialEq)]
|
|
pub struct AstString {
|
|
pub value: String,
|
|
pub pos: usize
|
|
}
|
|
#[derive(Debug, Clone, PartialEq)]
|
|
pub struct AstNumber {
|
|
pub value: f64,
|
|
pub pos: usize
|
|
}
|
|
#[derive(Debug, Clone, PartialEq)]
|
|
pub struct AstBool {
|
|
pub value: bool,
|
|
pub pos: usize
|
|
}
|
|
#[derive(Debug, Clone, PartialEq)]
|
|
pub struct AstNull {
|
|
pub pos: usize
|
|
}
|
|
#[derive(Debug, Clone, PartialEq)]
|
|
pub struct AstAssigment {
|
|
pub variable: String,
|
|
pub value: Box<ASTPart>,
|
|
pub pos: usize
|
|
}
|
|
#[derive(Debug, Clone, PartialEq)]
|
|
pub struct AstOperation {
|
|
pub operator: String,
|
|
pub left: Box<ASTPart>,
|
|
pub right: Box<ASTPart>,
|
|
pub pos: usize
|
|
}
|
|
#[derive(Debug, Clone, PartialEq)]
|
|
pub struct AstVarRead {
|
|
pub variable: String,
|
|
pub pos: usize
|
|
}
|
|
#[derive(Debug, Clone, PartialEq)]
|
|
pub struct AstCall {
|
|
pub function: Box<ASTPart>,
|
|
pub args: Vec<ASTPart>,
|
|
pub pos: usize
|
|
}
|
|
#[derive(Debug, Clone, PartialEq)]
|
|
pub struct AstVarUpdate {
|
|
pub variable: String,
|
|
pub value: Box<ASTPart>,
|
|
pub pos: usize
|
|
}
|
|
#[derive(Debug, Clone, PartialEq)]
|
|
pub struct AstFunction {
|
|
pub args: Vec<String>,
|
|
pub body: Vec<ASTPart>,
|
|
pub pos: usize
|
|
}
|
|
#[derive(Debug, Clone, PartialEq)]
|
|
pub struct AstIf {
|
|
pub condition: Box<ASTPart>,
|
|
pub body: Vec<ASTPart>,
|
|
pub pos: usize
|
|
}
|
|
#[derive(Debug, Clone, PartialEq)]
|
|
pub struct AstElseIf {
|
|
pub condition: Box<ASTPart>,
|
|
pub body: Vec<ASTPart>,
|
|
pub pos: usize
|
|
}
|
|
#[derive(Debug, Clone, PartialEq)]
|
|
pub struct AstElse {
|
|
pub body: Vec<ASTPart>,
|
|
pub pos: usize
|
|
}
|
|
#[derive(Debug, Clone, PartialEq)]
|
|
pub struct AstWhile {
|
|
pub condition: Box<ASTPart>,
|
|
pub body: Vec<ASTPart>,
|
|
pub pos: usize
|
|
}
|
|
#[derive(Debug, Clone, PartialEq)]
|
|
pub struct AstBreak {
|
|
pub pos: usize
|
|
}
|
|
#[derive(Debug, Clone, PartialEq)]
|
|
pub struct AstFor {
|
|
pub init: Box<ASTPart>,
|
|
pub condition: Box<ASTPart>,
|
|
pub update: Box<ASTPart>,
|
|
pub body: Vec<ASTPart>,
|
|
pub pos: usize
|
|
}
|
|
#[derive(Debug, Clone, PartialEq)]
|
|
pub struct AstContinue {
|
|
pub pos: usize
|
|
}
|
|
#[derive(Debug, Clone, PartialEq)]
|
|
pub struct AstReturn {
|
|
pub value: Box<ASTPart>,
|
|
pub pos: usize
|
|
}
|
|
#[derive(Debug, Clone, PartialEq)]
|
|
pub struct AstTable {
|
|
pub values: Vec<TableValue>,
|
|
pub pos: usize
|
|
}
|
|
#[derive(Debug, Clone, PartialEq)]
|
|
pub struct TableValue {
|
|
pub key: ASTPart,
|
|
pub value: ASTPart,
|
|
pub pos: usize
|
|
}
|
|
#[derive(Debug, Clone, PartialEq)]
|
|
pub struct AstTableGet {
|
|
pub table: Box<ASTPart>,
|
|
pub key: Box<ASTPart>,
|
|
pub pos: usize
|
|
}
|
|
#[derive(Debug, Clone, PartialEq)]
|
|
pub struct AstTableSet {
|
|
pub table: Box<ASTPart>,
|
|
pub key: Box<ASTPart>,
|
|
pub value: Box<ASTPart>,
|
|
pub pos: usize
|
|
}
|
|
#[derive(Debug, Clone, PartialEq)]
|
|
pub struct AstImport {
|
|
pub path: String,
|
|
pub pos: usize
|
|
}
|
|
#[derive(Debug, Clone, PartialEq)]
|
|
pub struct AstTryCatch {
|
|
pub try_block: AstFunction,
|
|
pub catch_block: AstFunction,
|
|
pub pos: usize
|
|
}
|
|
|
|
fn is_end(input: &Token, end: &Vec<Token>) -> bool {
|
|
for token in end {
|
|
if input.typ == token.typ && (token.value == "" || input.value == token.value) {
|
|
return true;
|
|
}
|
|
}
|
|
return false;
|
|
}
|
|
|
|
fn read_call(variable: ASTPart, pos: &mut usize, input: &Vec<Token>, ctx: &Context) -> ASTPart {
|
|
let mut args: Vec<ASTPart> = vec![];
|
|
*pos += 1;
|
|
let start_pos = input[*pos-1].pos;
|
|
while pos < &mut input.len() {
|
|
let token = &input[*pos];
|
|
if token.typ == TokenType::SEPARATOR && token.value == "," {
|
|
*pos += 1;
|
|
continue;
|
|
}
|
|
if token.typ == TokenType::SEPARATOR && token.value == String::from(")") {
|
|
*pos += 1;
|
|
break;
|
|
}
|
|
let ends: Vec<Token> = vec![
|
|
Token { typ: TokenType::SEPARATOR, value: String::from(","), pos: 0 },
|
|
Token { typ: TokenType::SEPARATOR, value: String::from(")"), pos: 0 }
|
|
];
|
|
let arg = read_exp(pos, input, &ends, &ends, ctx);
|
|
args.push(arg);
|
|
}
|
|
return ASTPart::Call(AstCall { function: Box::new(variable), args: args, pos: start_pos });
|
|
}
|
|
|
|
fn operator_precedence(op: &str) -> i64 {
|
|
match op {
|
|
"|" | "&" => 1,
|
|
"==" | "!=" | "<=" | ">=" => 2,
|
|
"+" | "-" => 3,
|
|
"*" | "/" | "%" => 4,
|
|
"^" => 5,
|
|
_ => 0
|
|
}
|
|
}
|
|
|
|
fn shunt(input: Vec<ASTPart>, ctx: &Context) -> ASTPart {
|
|
let mut output: Vec<ASTPart> = vec![];
|
|
let mut stack: Vec<ASTPart> = vec![];
|
|
for part in input {
|
|
match &part {
|
|
ASTPart::String(_) => {
|
|
output.push(part);
|
|
},
|
|
ASTPart::Number(_) => {
|
|
output.push(part);
|
|
},
|
|
ASTPart::Call(_) => {
|
|
output.push(part);
|
|
},
|
|
ASTPart::VarRead(_) => {
|
|
output.push(part);
|
|
},
|
|
ASTPart::Boolean(_) => {
|
|
output.push(part);
|
|
},
|
|
ASTPart::Null(_) => {
|
|
output.push(part);
|
|
},
|
|
ASTPart::Function(_) => {
|
|
output.push(part);
|
|
},
|
|
ASTPart::Table(_) => {
|
|
output.push(part);
|
|
},
|
|
ASTPart::TableGet(_) => {
|
|
output.push(part);
|
|
},
|
|
ASTPart::Operation(op) => {
|
|
if *op.left != ASTPart::NOOP && *op.right != ASTPart::NOOP {
|
|
output.push(part);
|
|
continue;
|
|
}
|
|
while stack.len() > 0 {
|
|
let top = &stack[stack.len()-1];
|
|
match top {
|
|
ASTPart::Operation(top_op) => {
|
|
if operator_precedence(&top_op.operator) >= operator_precedence(&op.operator) {
|
|
output.push(stack.pop().unwrap());
|
|
} else {
|
|
break;
|
|
}
|
|
},
|
|
_ => break
|
|
}
|
|
}
|
|
stack.push(part);
|
|
},
|
|
_ => {}
|
|
}
|
|
}
|
|
while stack.len() > 0 {
|
|
output.push(stack.pop().unwrap());
|
|
}
|
|
let mut i = 0;
|
|
while i < output.len() {
|
|
match &output[i] {
|
|
ASTPart::Operation(op) => {
|
|
if *op.left != ASTPart::NOOP && *op.right != ASTPart::NOOP {
|
|
i += 1;
|
|
continue;
|
|
}
|
|
if op.operator == "!" {
|
|
println!("{:?}", output);
|
|
if i < 1 {
|
|
let err = create_error(&format!("Unexpected operation `{}`", op.operator), op.pos, ErrorType::SemanticError, ErrorSubType::UnexpectedOperation, ctx);
|
|
print_error(&err, &ctx);
|
|
process::exit(1);
|
|
}
|
|
let left = output[i-1].clone();
|
|
output[i] = ASTPart::Operation(AstOperation {
|
|
operator: op.operator.clone(),
|
|
left: Box::new(left),
|
|
right: Box::new(ASTPart::NOOP),
|
|
pos: op.pos,
|
|
});
|
|
output.remove(i-1);
|
|
} else {
|
|
if i < 2 {
|
|
let err = create_error(&format!("Unexpected operation `{}`", op.operator), op.pos, ErrorType::SemanticError, ErrorSubType::UnexpectedOperation, ctx);
|
|
print_error(&err, &ctx);
|
|
process::exit(1);
|
|
}
|
|
let left = output[i-2].clone();
|
|
let right = output[i-1].clone();
|
|
output[i] = ASTPart::Operation(AstOperation {
|
|
operator: op.operator.clone(),
|
|
left: Box::new(left),
|
|
right: Box::new(right),
|
|
pos: op.pos,
|
|
});
|
|
output.remove(i-2);
|
|
output.remove(i-2);
|
|
i -= 1;
|
|
}
|
|
}
|
|
_ => {
|
|
i += 1;
|
|
}
|
|
}
|
|
}
|
|
if output.len() == 0 {
|
|
let err = create_error(&format!("No expressions found after applying order of operations"), 0, ErrorType::SemanticError, ErrorSubType::NoExpression, ctx);
|
|
print_error(&err, &ctx);
|
|
process::exit(1);
|
|
}
|
|
return output[0].clone();
|
|
}
|
|
fn read_function(input: &Vec<Token>, pos: &mut usize, with_args: bool, ctx: &Context) -> ASTPart {
|
|
let mut args: Vec<String> = vec![];
|
|
let start_pos = input[*pos].pos;
|
|
if with_args {
|
|
if input[*pos].typ != TokenType::SEPARATOR || input[*pos].value != "(" {
|
|
let err = create_error(&format!("Expected `(`"), input[*pos].pos, ErrorType::SyntaxError, ErrorSubType::Expected, ctx);
|
|
print_error(&err, &ctx);
|
|
process::exit(1);
|
|
}
|
|
*pos += 1;
|
|
while pos < &mut input.len() {
|
|
let token = &input[*pos];
|
|
if token.typ == TokenType::SEPARATOR && token.value == ")" {
|
|
break;
|
|
}
|
|
*pos += 1;
|
|
if token.typ == TokenType::SEPARATOR && token.value == "," {
|
|
continue;
|
|
}
|
|
if token.typ == TokenType::IDENTIFIER {
|
|
args.push(token.value.clone());
|
|
} else {
|
|
let err = create_error(&format!("Unexpected `{:?}({})`", token.typ, token.value), token.pos, ErrorType::SyntaxError, ErrorSubType::Unexpected, ctx);
|
|
print_error(&err, &ctx);
|
|
process::exit(1);
|
|
}
|
|
}
|
|
if input[*pos].typ != TokenType::SEPARATOR || input[*pos].value != ")" {
|
|
let err = create_error(&format!("Unexpected end of arguments"), input[*pos].pos, ErrorType::SyntaxError, ErrorSubType::UnexpectedEnd, ctx);
|
|
print_error(&err, &ctx);
|
|
process::exit(1);
|
|
}
|
|
*pos += 1;
|
|
}
|
|
if input[*pos].typ != TokenType::SEPARATOR || input[*pos].value != "{" {
|
|
let err = create_error(&format!("Expected {{"), input[*pos].pos, ErrorType::SyntaxError, ErrorSubType::Expected, ctx);
|
|
print_error(&err, &ctx);
|
|
process::exit(1);
|
|
}
|
|
*pos += 1;
|
|
let op_ends: Vec<Token> = vec![
|
|
Token { typ: TokenType::OPEND, value: String::from("\n"), pos: 0 },
|
|
Token { typ: TokenType::OPEND, value: String::from(";"), pos: 0 },
|
|
Token { typ: TokenType::SEPARATOR, value: String::from("}"), pos: 0 }
|
|
];
|
|
let parse_ends: Vec<Token> = vec![
|
|
Token { typ: TokenType::SEPARATOR, value: String::from("}"), pos: 0 }
|
|
];
|
|
let body = parse_internal(input, &op_ends, &parse_ends, pos, ctx);
|
|
if input[*pos].typ != TokenType::SEPARATOR || input[*pos].value != "}" {
|
|
let err = create_error(&format!("Unexpected end of function"), input[*pos].pos, ErrorType::SyntaxError, ErrorSubType::UnexpectedEnd, ctx);
|
|
print_error(&err, &ctx);
|
|
process::exit(1);
|
|
}
|
|
*pos += 1;
|
|
return ASTPart::Function(AstFunction { args: args, body: body, pos: start_pos });
|
|
}
|
|
|
|
fn read_table(input: &Vec<Token>, pos: &mut usize, ctx: &Context) -> ASTPart {
|
|
let start_pos = input[*pos].pos;
|
|
let key_ends: Vec<Token> = vec![
|
|
Token { typ: TokenType::SEPARATOR, value: String::from("]"), pos: 0 },
|
|
];
|
|
let ends: Vec<Token> = vec![
|
|
Token { typ: TokenType::SEPARATOR, value: String::from("}"), pos: 0 },
|
|
Token { typ: TokenType::SEPARATOR, value: String::from(","), pos: 0 },
|
|
Token { typ: TokenType::OPEND, value: String::from("\n"), pos: 0 },
|
|
];
|
|
let mut tbl: Vec<TableValue> = vec![];
|
|
let mut key = 0;
|
|
while *pos < input.len() {
|
|
if input[*pos].typ == TokenType::OPEND && input[*pos].value == "\n" {
|
|
*pos += 1;
|
|
continue;
|
|
} else if input[*pos].typ == TokenType::SEPARATOR && input[*pos].value == "}" {
|
|
*pos += 1;
|
|
break;
|
|
}
|
|
if input[*pos].typ == TokenType::SEPARATOR && input[*pos].value == "[" {
|
|
*pos += 1;
|
|
let keyy = read_exp(pos, input, &key_ends, &key_ends, ctx);
|
|
match keyy {
|
|
ASTPart::Table(_) => {
|
|
let err = create_error(&format!("Table keys cannot be tables"), input[*pos].pos, ErrorType::SemanticError, ErrorSubType::InvalidTableKeys, ctx);
|
|
print_error(&err, &ctx);
|
|
process::exit(1);
|
|
},
|
|
ASTPart::Function(_) => {
|
|
let err = create_error(&format!("Table keys cannot be functions"), input[*pos].pos, ErrorType::SemanticError, ErrorSubType::InvalidTableKeys, ctx);
|
|
print_error(&err, &ctx);
|
|
process::exit(1);
|
|
},
|
|
_ => {}
|
|
}
|
|
if input[*pos].typ != TokenType::SEPARATOR || input[*pos].value != "]" {
|
|
let err = create_error(&format!("Unexpected end of key"), input[*pos].pos, ErrorType::SyntaxError, ErrorSubType::UnexpectedEnd, ctx);
|
|
print_error(&err, &ctx);
|
|
process::exit(1);
|
|
}
|
|
*pos += 1;
|
|
if input[*pos].typ != TokenType::SEPARATOR || input[*pos].value != "=" {
|
|
let err = create_error(&format!("Expected `=` after key"), input[*pos].pos, ErrorType::SyntaxError, ErrorSubType::Expected, ctx);
|
|
print_error(&err, &ctx);
|
|
process::exit(1);
|
|
}
|
|
*pos += 1;
|
|
let value = read_exp(pos, input, &ends, &ends, ctx);
|
|
tbl.push(TableValue { key: keyy, value: value, pos: input[*pos].pos });
|
|
} else {
|
|
let value = read_exp(pos, input, &ends, &ends, ctx);
|
|
tbl.push(TableValue { key: ASTPart::Number(AstNumber { value: key as f64, pos: 0 }), value: value, pos: input[*pos].pos });
|
|
key += 1;
|
|
}
|
|
if input[*pos].typ == TokenType::SEPARATOR && input[*pos].value == "}" {
|
|
*pos += 1;
|
|
break;
|
|
} else if input[*pos].typ == TokenType::SEPARATOR && input[*pos].value == "," {
|
|
*pos += 1;
|
|
continue;
|
|
} else if input[*pos].typ == TokenType::OPEND && input[*pos].value == "\n" {
|
|
*pos += 1;
|
|
continue;
|
|
} else {
|
|
let err = create_error(&format!("Unexpected end of table"), input[*pos].pos, ErrorType::SyntaxError, ErrorSubType::UnexpectedEnd, ctx);
|
|
print_error(&err, &ctx);
|
|
process::exit(1);
|
|
}
|
|
}
|
|
return ASTPart::Table(AstTable { values: tbl, pos: start_pos });
|
|
}
|
|
|
|
fn read_exp(pos: &mut usize, input: &Vec<Token>, ends: &Vec<Token>, parse_ends: &Vec<Token>, ctx: &Context) -> ASTPart {
|
|
let mut expressions: Vec<ASTPart> = vec![];
|
|
while pos < &mut input.len() {
|
|
let token = &input[*pos];
|
|
let mut next_token = &Token {
|
|
typ: TokenType::OPEND,
|
|
value: String::from("END"),
|
|
pos: 0
|
|
};
|
|
if *pos+1 < input.len() {
|
|
next_token = &input[*pos+1]
|
|
}
|
|
if is_end(token, &parse_ends) {
|
|
break;
|
|
}
|
|
*pos += 1;
|
|
if is_end(token, ends) {
|
|
break;
|
|
}
|
|
if token.typ == TokenType::STRING {
|
|
expressions.push(ASTPart::String(AstString { value: token.value.clone(), pos: token.pos }));
|
|
} else if token.typ == TokenType::NUMBER {
|
|
if expressions.len() == 1 {
|
|
match &expressions[0] {
|
|
ASTPart::Operation(op) => {
|
|
if op.operator == "+" || op.operator == "-" {
|
|
let mut nm = op.operator.clone();
|
|
nm.push_str(&token.value);
|
|
expressions.push(ASTPart::Number(AstNumber { value: nm.parse().unwrap(), pos: token.pos }));
|
|
expressions.remove(0);
|
|
} else {
|
|
expressions.push(ASTPart::Number(AstNumber { value: token.value.parse().unwrap(), pos: token.pos }));
|
|
}
|
|
},
|
|
_ => {
|
|
expressions.push(ASTPart::Number(AstNumber { value: token.value.parse().unwrap(), pos: token.pos }));
|
|
}
|
|
}
|
|
} else {
|
|
expressions.push(ASTPart::Number(AstNumber { value: token.value.parse().unwrap(), pos: token.pos }));
|
|
}
|
|
} else if token.typ == TokenType::KEYWORD {
|
|
if token.value == "piszv" {
|
|
expressions.push(ASTPart::Boolean(AstBool { value: true, pos: token.pos }));
|
|
} else if token.value == "nem piszv" {
|
|
expressions.push(ASTPart::Boolean(AstBool { value: false, pos: token.pos }));
|
|
} else if token.value == "nincs hám" {
|
|
expressions.push(ASTPart::Null(AstNull { pos: token.pos }));
|
|
} else if token.value == "lőcsve" {
|
|
let func = read_function(input, pos, true, ctx);
|
|
expressions.push(func);
|
|
} else {
|
|
let err = create_error(&format!("Unexpected `{:?}({})`", token.typ, token.value), token.pos, ErrorType::SyntaxError, ErrorSubType::Unexpected, ctx);
|
|
print_error(&err, &ctx);
|
|
process::exit(1);
|
|
}
|
|
} else if token.typ == TokenType::IDENTIFIER {
|
|
if next_token.typ == TokenType::SEPARATOR && next_token.value == "(" {
|
|
let var = ASTPart::VarRead(AstVarRead { variable: token.value.clone(), pos: token.pos });
|
|
let cal = read_call(var, pos, input, ctx);
|
|
expressions.push(check_continue(pos, input, cal, parse_ends, parse_ends, ctx));
|
|
} else if next_token.typ == TokenType::SEPARATOR && next_token.value == "[" {
|
|
let var_pos = token.pos;
|
|
let key_ends: Vec<Token> = vec![
|
|
Token { typ: TokenType::SEPARATOR, value: String::from("]"), pos: 0 }
|
|
];
|
|
*pos += 1;
|
|
let keyy = read_exp(pos, input, &key_ends, &key_ends, ctx);
|
|
match keyy {
|
|
ASTPart::Table(_) => {
|
|
let err = create_error(&format!("Table keys cannot be tables"), input[*pos].pos, ErrorType::SemanticError, ErrorSubType::InvalidTableKeys, ctx);
|
|
print_error(&err, &ctx);
|
|
process::exit(1);
|
|
},
|
|
ASTPart::Function(_) => {
|
|
let err = create_error(&format!("Table keys cannot be functions"), input[*pos].pos, ErrorType::SemanticError, ErrorSubType::InvalidTableKeys, ctx);
|
|
print_error(&err, &ctx);
|
|
process::exit(1);
|
|
},
|
|
_ => {}
|
|
}
|
|
if input[*pos].typ != TokenType::SEPARATOR || input[*pos].value != "]" {
|
|
let err = create_error(&format!("Unexpected end of key"), input[*pos].pos, ErrorType::SyntaxError, ErrorSubType::UnexpectedEnd, ctx);
|
|
print_error(&err, &ctx);
|
|
process::exit(1);
|
|
}
|
|
*pos += 1;
|
|
let gt = ASTPart::TableGet(AstTableGet { table: Box::new(ASTPart::VarRead(AstVarRead { variable: token.value.clone(), pos: var_pos })), key: Box::new(keyy), pos: var_pos+1 });
|
|
expressions.push(check_continue(pos, input, gt, parse_ends, parse_ends, ctx));
|
|
} else if next_token.typ == TokenType::SEPARATOR && next_token.value == "." {
|
|
let var_pos = token.pos;
|
|
*pos += 1;
|
|
let keyy = &input[*pos];
|
|
if keyy.typ != TokenType::IDENTIFIER {
|
|
let err = create_error(&format!("Expected identifier after `.`"), keyy.pos, ErrorType::SyntaxError, ErrorSubType::Expected, ctx);
|
|
print_error(&err, &ctx);
|
|
process::exit(1);
|
|
}
|
|
*pos += 1;
|
|
let gt = ASTPart::TableGet(AstTableGet { table: Box::new(ASTPart::VarRead(AstVarRead { variable: token.value.clone(), pos: var_pos })), key: Box::new(ASTPart::String(AstString { value: keyy.value.clone(), pos: keyy.pos })), pos: var_pos+1 });
|
|
expressions.push(check_continue(pos, input, gt, parse_ends, parse_ends, ctx));
|
|
} else {
|
|
expressions.push(ASTPart::VarRead(AstVarRead { variable: token.value.clone(), pos: token.pos }));
|
|
}
|
|
} else if token.typ == TokenType::OPERATOR {
|
|
expressions.push(ASTPart::Operation(AstOperation { operator: token.value.clone(), left: Box::new(ASTPart::NOOP), right: Box::new(ASTPart::NOOP), pos: token.pos }));
|
|
} else if token.typ == TokenType::SEPARATOR {
|
|
//We check for () and then send the into read_exp again, so we recursively parse the expression
|
|
if token.value == "(" {
|
|
let ends: Vec<Token> = vec![
|
|
Token { typ: TokenType::SEPARATOR, value: String::from(")"), pos: 0 }
|
|
];
|
|
let exp = read_exp(pos, input, &ends, &ends, ctx);
|
|
if input[*pos].typ == TokenType::SEPARATOR && input[*pos].value == ")" {
|
|
*pos += 1;
|
|
} else {
|
|
let err = create_error(&format!("Unclosed parenthesis"), input[*pos].pos, ErrorType::SyntaxError, ErrorSubType::Unclosed, ctx);
|
|
print_error(&err, &ctx);
|
|
process::exit(1);
|
|
}
|
|
expressions.push(exp);
|
|
} else if token.value == "{" {
|
|
let tbl = read_table(input, pos, ctx);
|
|
expressions.push(tbl);
|
|
} else {
|
|
let err = create_error(&format!("Unexpected `{:?}({})`", token.typ, token.value), token.pos, ErrorType::SyntaxError, ErrorSubType::Unexpected, ctx);
|
|
print_error(&err, &ctx);
|
|
process::exit(1);
|
|
}
|
|
} else {
|
|
let err = create_error(&format!("Unexpected `{:?}({})`", token.typ, token.value), token.pos, ErrorType::SyntaxError, ErrorSubType::Unexpected, ctx);
|
|
print_error(&err, &ctx);
|
|
process::exit(1);
|
|
}
|
|
}
|
|
let shunted = shunt(expressions, ctx);
|
|
return shunted;
|
|
}
|
|
|
|
fn check_continue(pos: &mut usize, input: &Vec<Token>, prev: ASTPart, op_ends: &Vec<Token>, parse_ends: &Vec<Token>, ctx: &Context) -> ASTPart {
|
|
let token = &input[*pos];
|
|
if is_end(token, &parse_ends) {
|
|
return prev;
|
|
}
|
|
if is_end(token, &op_ends) {
|
|
return prev;
|
|
}
|
|
if token.typ == TokenType::SEPARATOR && token.value == "(" {
|
|
let cal = read_call(prev, pos, input, ctx);
|
|
return check_continue(pos, input, cal, op_ends, parse_ends, ctx)
|
|
}
|
|
if token.typ == TokenType::SEPARATOR && token.value == "[" {
|
|
let var_pos = token.pos;
|
|
*pos += 1;
|
|
let key_ends: Vec<Token> = vec![
|
|
Token { typ: TokenType::SEPARATOR, value: String::from("]"), pos: 0 }
|
|
];
|
|
let keyy = read_exp(pos, input, &key_ends, &key_ends, ctx);
|
|
match keyy {
|
|
ASTPart::Table(_) => {
|
|
let err = create_error(&format!("Table keys cannot be tables"), input[*pos].pos, ErrorType::SemanticError, ErrorSubType::InvalidTableKeys, ctx);
|
|
print_error(&err, &ctx);
|
|
process::exit(1);
|
|
},
|
|
ASTPart::Function(_) => {
|
|
let err = create_error(&format!("Table keys cannot be functions"), input[*pos].pos, ErrorType::SemanticError, ErrorSubType::InvalidTableKeys, ctx);
|
|
print_error(&err, &ctx);
|
|
process::exit(1);
|
|
},
|
|
_ => {}
|
|
}
|
|
if input[*pos].typ != TokenType::SEPARATOR || input[*pos].value != "]" {
|
|
let err = create_error(&format!("Unexpected end of key"), input[*pos].pos, ErrorType::SyntaxError, ErrorSubType::UnexpectedEnd, ctx);
|
|
print_error(&err, &ctx);
|
|
process::exit(1);
|
|
}
|
|
*pos += 1;
|
|
let gt = ASTPart::TableGet(AstTableGet { table: Box::new(prev), key: Box::new(keyy), pos: var_pos+1 });
|
|
return check_continue(pos, input, gt, op_ends, parse_ends, ctx);
|
|
} else if token.typ == TokenType::SEPARATOR && token.value == "." {
|
|
let var_pos = token.pos;
|
|
*pos += 1;
|
|
let keyy = &input[*pos];
|
|
if keyy.typ != TokenType::IDENTIFIER {
|
|
let err = create_error(&format!("Expected identifier after `.`"), keyy.pos, ErrorType::SyntaxError, ErrorSubType::Expected, ctx);
|
|
print_error(&err, &ctx);
|
|
process::exit(1);
|
|
}
|
|
*pos += 1;
|
|
let gt = ASTPart::TableGet(AstTableGet { table: Box::new(prev), key: Box::new(ASTPart::String(AstString { value: keyy.value.clone(), pos: keyy.pos })), pos: var_pos+1 });
|
|
return check_continue(pos, input, gt, op_ends, parse_ends, ctx);
|
|
}
|
|
return prev;
|
|
}
|
|
|
|
fn next_operation(pos: &mut usize, input: &Vec<Token>, op_ends: &Vec<Token>, parse_ends: &Vec<Token>, ctx: &Context) -> ASTPart {
|
|
let token = &input[*pos];
|
|
let mut next_token = &Token {
|
|
typ: TokenType::OPEND,
|
|
value: String::from("END"),
|
|
pos: 0
|
|
};
|
|
if *pos+1 < input.len() {
|
|
next_token = &input[*pos+1]
|
|
}
|
|
if is_end(token, &parse_ends) {
|
|
return ASTPart::NOOP;
|
|
}
|
|
*pos += 1;
|
|
if is_end(token, &op_ends) {
|
|
return ASTPart::NOOP;
|
|
}
|
|
if token.typ == TokenType::KEYWORD {
|
|
if token.value == "gethelj" {
|
|
let variable = &input[*pos];
|
|
*pos += 1;
|
|
if variable.typ != TokenType::IDENTIFIER {
|
|
let err = create_error(&format!("Unexpected `{:?}`", variable.typ,), token.pos, ErrorType::SyntaxError, ErrorSubType::Unexpected, ctx);
|
|
print_error(&err, &ctx);
|
|
process::exit(1);
|
|
}
|
|
let eq = &input[*pos];
|
|
if eq.typ == TokenType::SEPARATOR && eq.value == "=" {
|
|
*pos += 1;
|
|
}
|
|
let value = read_exp(pos, input, op_ends, parse_ends, ctx);
|
|
return ASTPart::Assigment(AstAssigment { variable: variable.value.clone(), value: Box::new(value), pos: token.pos });
|
|
} else if token.value == "ha geny" {
|
|
if next_token.typ != TokenType::SEPARATOR || next_token.value != "(" {
|
|
let err = create_error(&format!("Expected `(`"), token.pos, ErrorType::SyntaxError, ErrorSubType::Expected, ctx);
|
|
print_error(&err, &ctx);
|
|
process::exit(1);
|
|
}
|
|
*pos += 1;
|
|
let condition_end = vec![
|
|
Token { typ: TokenType::SEPARATOR, value: String::from(")"), pos: 0 }
|
|
];
|
|
let condition = read_exp(pos, input, &condition_end, &condition_end, ctx);
|
|
if input[*pos].typ != TokenType::SEPARATOR || input[*pos].value != ")" {
|
|
let err = create_error(&format!("Unexpected end of condition"), token.pos, ErrorType::SyntaxError, ErrorSubType::UnexpectedEnd, ctx);
|
|
print_error(&err, &ctx);
|
|
process::exit(1);
|
|
}
|
|
*pos += 1;
|
|
let body = read_function(input, pos, false, ctx);
|
|
let real_body = match body {
|
|
ASTPart::Function(func) => func.body,
|
|
_ => {
|
|
let err = create_error(&format!("Expected function body"), token.pos, ErrorType::SyntaxError, ErrorSubType::Expected, ctx);
|
|
print_error(&err, &ctx);
|
|
process::exit(1);
|
|
}
|
|
};
|
|
return ASTPart::If(AstIf { condition: Box::new(condition), body: real_body, pos: token.pos });
|
|
} else if token.value == "amíg geny" {
|
|
if next_token.typ != TokenType::SEPARATOR || next_token.value != "(" {
|
|
let err = create_error(&format!("Expected `(`"), token.pos, ErrorType::SyntaxError, ErrorSubType::Expected, ctx);
|
|
print_error(&err, &ctx);
|
|
process::exit(1);
|
|
}
|
|
*pos += 1;
|
|
let condition_end = vec![
|
|
Token { typ: TokenType::SEPARATOR, value: String::from(")"), pos: 0 }
|
|
];
|
|
let condition = read_exp(pos, input, &condition_end, &condition_end, ctx);
|
|
if input[*pos].typ != TokenType::SEPARATOR || input[*pos].value != ")" {
|
|
let err = create_error(&format!("Unexpected end of condition"), token.pos, ErrorType::SyntaxError, ErrorSubType::UnexpectedEnd, ctx);
|
|
print_error(&err, &ctx);
|
|
process::exit(1);
|
|
}
|
|
*pos += 1;
|
|
let body = read_function(input, pos, false, ctx);
|
|
let real_body = match body {
|
|
ASTPart::Function(func) => func.body,
|
|
_ => {
|
|
let err = create_error(&format!("Expected function body"), token.pos, ErrorType::SyntaxError, ErrorSubType::Expected, ctx);
|
|
print_error(&err, &ctx);
|
|
process::exit(1);
|
|
}
|
|
};
|
|
return ASTPart::While(AstWhile { condition: Box::new(condition), body: real_body, pos: token.pos });
|
|
} else if token.value == "kraf" {
|
|
return ASTPart::Break(AstBreak { pos: token.pos });
|
|
} else if token.value == "kopva" {
|
|
if next_token.typ != TokenType::SEPARATOR || next_token.value != "(" {
|
|
let err = create_error(&format!("Expected `(`"), token.pos, ErrorType::SyntaxError, ErrorSubType::Expected, ctx);
|
|
print_error(&err, &ctx);
|
|
process::exit(1);
|
|
}
|
|
*pos += 1;
|
|
let ends = vec![
|
|
Token { typ: TokenType::SEPARATOR, value: String::from(")"), pos: 0 },
|
|
Token { typ: TokenType::OPEND, value: String::from(";"), pos: 0 }
|
|
];
|
|
let init = parse_internal(input, &ends, &ends, pos, ctx);
|
|
if init.len() != 1 {
|
|
let err = create_error(&format!("Only one expression is expected for init"), token.pos, ErrorType::SyntaxError, ErrorSubType::Expected, ctx);
|
|
print_error(&err, &ctx);
|
|
process::exit(1);
|
|
}
|
|
if input[*pos].typ != TokenType::OPEND || input[*pos].value != ";" {
|
|
let err = create_error(&format!("Unexpected end of init"), token.pos, ErrorType::SyntaxError, ErrorSubType::UnexpectedEnd, ctx);
|
|
print_error(&err, &ctx);
|
|
process::exit(1);
|
|
}
|
|
*pos += 1;
|
|
let condition = read_exp(pos, input, &ends, &ends, ctx);
|
|
if input[*pos].typ != TokenType::OPEND || input[*pos].value != ";" {
|
|
let err = create_error(&format!("Unexpected end of condition"), token.pos, ErrorType::SyntaxError, ErrorSubType::UnexpectedEnd, ctx);
|
|
print_error(&err, &ctx);
|
|
process::exit(1);
|
|
}
|
|
*pos += 1;
|
|
let update = parse_internal(input, &ends, &ends, pos, ctx);
|
|
if update.len() != 1 {
|
|
let err = create_error(&format!("Only one expression is expected for update"), token.pos, ErrorType::SyntaxError, ErrorSubType::Expected, ctx);
|
|
print_error(&err, &ctx);
|
|
process::exit(1);
|
|
}
|
|
if input[*pos].typ != TokenType::SEPARATOR || input[*pos].value != ")" {
|
|
let err = create_error(&format!("Unexpected end of update"), token.pos, ErrorType::SyntaxError, ErrorSubType::UnexpectedEnd, ctx);
|
|
print_error(&err, &ctx);
|
|
process::exit(1);
|
|
}
|
|
*pos += 1;
|
|
let body = read_function(input, pos, false, ctx);
|
|
let real_body = match body {
|
|
ASTPart::Function(func) => func.body,
|
|
_ => {
|
|
let err = create_error(&format!("Expected function body"), token.pos, ErrorType::SyntaxError, ErrorSubType::Expected, ctx);
|
|
print_error(&err, &ctx);
|
|
process::exit(1);
|
|
}
|
|
};
|
|
return ASTPart::For(AstFor { init: Box::new(init[0].clone()), condition: Box::new(condition), update: Box::new(update[0].clone()), body: real_body, pos: token.pos });
|
|
} else if token.value == "szard le" {
|
|
return ASTPart::Continue(AstContinue { pos: token.pos });
|
|
} else if token.value == "ha nem geny akkor geny" {
|
|
if next_token.typ != TokenType::SEPARATOR || next_token.value != "(" {
|
|
let err = create_error(&format!("Expected `(`"), token.pos, ErrorType::SyntaxError, ErrorSubType::Expected, ctx);
|
|
print_error(&err, &ctx);
|
|
process::exit(1);
|
|
}
|
|
*pos += 1;
|
|
let condition_end = vec![
|
|
Token { typ: TokenType::SEPARATOR, value: String::from(")"), pos: 0 }
|
|
];
|
|
let condition = read_exp(pos, input, &condition_end, &condition_end, ctx);
|
|
if input[*pos].typ != TokenType::SEPARATOR || input[*pos].value != ")" {
|
|
let err = create_error(&format!("Unexpected end of condition"), token.pos, ErrorType::SyntaxError, ErrorSubType::UnexpectedEnd, ctx);
|
|
print_error(&err, &ctx);
|
|
process::exit(1);
|
|
}
|
|
*pos += 1;
|
|
let body = read_function(input, pos, false, ctx);
|
|
let real_body = match body {
|
|
ASTPart::Function(func) => func.body,
|
|
_ => {
|
|
let err = create_error(&format!("Expected function body"), token.pos, ErrorType::SyntaxError, ErrorSubType::Expected, ctx);
|
|
print_error(&err, &ctx);
|
|
process::exit(1);
|
|
}
|
|
};
|
|
return ASTPart::ElseIf(AstElseIf { condition: Box::new(condition), body: real_body, pos: token.pos });
|
|
} else if token.value == "ha nem geny" {
|
|
let body = read_function(input, pos, false, ctx);
|
|
let real_body = match body {
|
|
ASTPart::Function(func) => func.body,
|
|
_ => {
|
|
let err = create_error(&format!("Expected function body"), token.pos, ErrorType::SyntaxError, ErrorSubType::Expected, ctx);
|
|
print_error(&err, &ctx);
|
|
process::exit(1);
|
|
}
|
|
};
|
|
return ASTPart::Else(AstElse { body: real_body, pos: token.pos });
|
|
} else if token.value == "reti" {
|
|
if is_end(next_token, op_ends) || is_end(next_token, parse_ends) {
|
|
return ASTPart::Return(AstReturn { value: Box::new(ASTPart::Null(AstNull { pos: token.pos })), pos: token.pos });
|
|
} else {
|
|
let value = read_exp(pos, input, op_ends, parse_ends, ctx);
|
|
return ASTPart::Return(AstReturn { value: Box::new(value), pos: token.pos });
|
|
}
|
|
} else if token.value == "hámozd" {
|
|
let var = &input[*pos];
|
|
*pos += 1;
|
|
if var.typ != TokenType::IDENTIFIER {
|
|
let err = create_error(&format!("Expected identifier after hámozd"), token.pos, ErrorType::SyntaxError, ErrorSubType::Expected, ctx);
|
|
print_error(&err, &ctx);
|
|
process::exit(1);
|
|
}
|
|
if input[*pos].typ != TokenType::KEYWORD || (input[*pos].value != "be" && input[*pos].value != "ba") {
|
|
let err = create_error(&format!("Expected `be`/`ba` after hámozd"), input[*pos].pos, ErrorType::SyntaxError, ErrorSubType::Expected, ctx);
|
|
print_error(&err, &ctx);
|
|
process::exit(1);
|
|
}
|
|
*pos += 1;
|
|
let path = &input[*pos];
|
|
if path.typ != TokenType::STRING {
|
|
let err = create_error(&format!("Expected string for hámozd"), path.pos, ErrorType::SyntaxError, ErrorSubType::Expected, ctx);
|
|
print_error(&err, &ctx);
|
|
process::exit(1);
|
|
}
|
|
*pos += 1;
|
|
return ASTPart::Assigment(AstAssigment { variable: var.value.clone(), value: Box::new(ASTPart::Import(AstImport { path: path.value.clone(), pos: token.pos })), pos: token.pos });
|
|
} else if token.value == "lőcsve" {
|
|
if next_token.typ == TokenType::IDENTIFIER {
|
|
*pos += 1;
|
|
let func = read_function(input, pos, true, ctx);
|
|
return ASTPart::Assigment(AstAssigment { variable: next_token.value.clone(), value: Box::new(func), pos: *pos - 1 });
|
|
} else {
|
|
let func = read_function(input, pos, true, ctx);
|
|
return check_continue(pos, input, func, op_ends, parse_ends, ctx);
|
|
}
|
|
} else if token.value == "piszolj" {
|
|
let func = read_function(input, pos, false, ctx);
|
|
let tryp = match func {
|
|
ASTPart::Function(f) => f,
|
|
_ => {
|
|
let err = create_error(&format!("Expected function body"), token.pos, ErrorType::SyntaxError, ErrorSubType::Expected, ctx);
|
|
print_error(&err, &ctx);
|
|
process::exit(1);
|
|
}
|
|
};
|
|
if input[*pos].typ != TokenType::KEYWORD || input[*pos].value != "csecs" {
|
|
let err = create_error(&format!("Expected `csecs` after piszolj"), input[*pos].pos, ErrorType::SyntaxError, ErrorSubType::Expected, ctx);
|
|
print_error(&err, &ctx);
|
|
process::exit(1);
|
|
}
|
|
*pos += 1;
|
|
let func2 = read_function(input, pos, true, ctx);
|
|
let catchp = match func2 {
|
|
ASTPart::Function(f) => f,
|
|
_ => {
|
|
let err = create_error(&format!("Expected function body"), input[*pos].pos, ErrorType::SyntaxError, ErrorSubType::Expected, ctx);
|
|
print_error(&err, &ctx);
|
|
process::exit(1);
|
|
}
|
|
};
|
|
return ASTPart::TryCatch(AstTryCatch { try_block: tryp, catch_block: catchp, pos: token.pos });
|
|
} else {
|
|
let err = create_error(&format!("Unexpected `{:?}({})`", token.typ, token.value), token.pos, ErrorType::SyntaxError, ErrorSubType::Unexpected, ctx);
|
|
print_error(&err, &ctx);
|
|
process::exit(1);
|
|
}
|
|
} else if token.typ == TokenType::IDENTIFIER {
|
|
if next_token.typ == TokenType::SEPARATOR && next_token.value == "(" {
|
|
let var = ASTPart::VarRead(AstVarRead { variable: token.value.clone(), pos: token.pos });
|
|
let cal = read_call(var, pos, input, ctx);
|
|
return check_continue(pos, input, cal, op_ends, parse_ends, ctx)
|
|
} else if next_token.typ == TokenType::SEPARATOR && next_token.value == "." {
|
|
let var_pos = token.pos;
|
|
*pos += 1;
|
|
let keyy = &input[*pos];
|
|
if keyy.typ != TokenType::IDENTIFIER {
|
|
let err = create_error(&format!("Expected identifier after `.`"), keyy.pos, ErrorType::SyntaxError, ErrorSubType::Expected, ctx);
|
|
print_error(&err, &ctx);
|
|
process::exit(1);
|
|
}
|
|
*pos += 1;
|
|
let gt = ASTPart::TableGet(AstTableGet { table: Box::new(ASTPart::VarRead(AstVarRead { variable: token.value.clone(), pos: var_pos })), key: Box::new(ASTPart::String(AstString { value: keyy.value.clone(), pos: keyy.pos })), pos: var_pos+1 });
|
|
return check_continue(pos, input, gt, op_ends, parse_ends, ctx);
|
|
} else if next_token.typ == TokenType::SEPARATOR && next_token.value == "[" {
|
|
*pos += 1;
|
|
let key_ends: Vec<Token> = vec![
|
|
Token { typ: TokenType::SEPARATOR, value: String::from("]"), pos: 0 }
|
|
];
|
|
let keyy = read_exp(pos, input, &key_ends, &key_ends, ctx);
|
|
match keyy {
|
|
ASTPart::Table(_) => {
|
|
let err = create_error(&format!("Table keys cannot be tables"), input[*pos].pos, ErrorType::SemanticError, ErrorSubType::InvalidTableKeys, ctx);
|
|
print_error(&err, &ctx);
|
|
process::exit(1);
|
|
},
|
|
ASTPart::Function(_) => {
|
|
let err = create_error(&format!("Table keys cannot be functions"), input[*pos].pos, ErrorType::SemanticError, ErrorSubType::InvalidTableKeys, ctx);
|
|
print_error(&err, &ctx);
|
|
process::exit(1);
|
|
},
|
|
_ => {}
|
|
}
|
|
if input[*pos].typ != TokenType::SEPARATOR || input[*pos].value != "]" {
|
|
let err = create_error(&format!("Unexpected end of key"), input[*pos].pos, ErrorType::SyntaxError, ErrorSubType::UnexpectedEnd, ctx);
|
|
print_error(&err, &ctx);
|
|
process::exit(1);
|
|
}
|
|
*pos += 1;
|
|
if input[*pos].typ == TokenType::SEPARATOR && input[*pos].value == "=" {
|
|
*pos += 1;
|
|
let value = read_exp(pos, input, op_ends, parse_ends, ctx);
|
|
return ASTPart::TableSet(AstTableSet { table: Box::new(ASTPart::VarRead(AstVarRead { variable: token.value.clone(), pos: token.pos })), key: Box::new(keyy), value: Box::new(value), pos: token.pos });
|
|
} else {
|
|
let gt = ASTPart::TableGet(AstTableGet { table: Box::new(ASTPart::VarRead(AstVarRead { variable: token.value.clone(), pos: token.pos })), key: Box::new(keyy.clone()), pos: token.pos });
|
|
return check_continue(pos, input, gt, op_ends, parse_ends, ctx);
|
|
}
|
|
} else if next_token.typ == TokenType::SEPARATOR && next_token.value == "=" {
|
|
*pos += 1;
|
|
let value = read_exp(pos, input, op_ends, parse_ends, ctx);
|
|
return ASTPart::VarUpdate(AstVarUpdate { variable: token.value.clone(), value: Box::new(value), pos: token.pos });
|
|
} else {
|
|
let err = create_error(&format!("Unexpected `{:?}({})`", token.typ, token.value), token.pos, ErrorType::SyntaxError, ErrorSubType::Unexpected, ctx);
|
|
print_error(&err, &ctx);
|
|
process::exit(1);
|
|
}
|
|
} else {
|
|
let err = create_error(&format!("Unexpected `{:?}({})`", token.typ, token.value), token.pos, ErrorType::SyntaxError, ErrorSubType::Unexpected, ctx);
|
|
print_error(&err, &ctx);
|
|
process::exit(1);
|
|
}
|
|
}
|
|
|
|
fn parse_internal(input: &Vec<Token>, op_ends: &Vec<Token>, parse_ends: &Vec<Token>, pos: &mut usize, ctx: &Context) -> Vec<ASTPart> {
|
|
let mut out: Vec<ASTPart> = vec![];
|
|
while *pos < input.len() {
|
|
let op = next_operation(pos, &input, &op_ends, &parse_ends, ctx);
|
|
match op {
|
|
ASTPart::NOOP => {},
|
|
_ => {
|
|
out.push(op);
|
|
}
|
|
}
|
|
if is_end(&input[*pos], &parse_ends) {
|
|
break;
|
|
}
|
|
}
|
|
return out;
|
|
}
|
|
pub fn parse(input: Vec<Token>, ctx: &Context) -> Vec<ASTPart> {
|
|
let op_ends: Vec<Token> = vec![
|
|
Token { typ: TokenType::OPEND, value: String::from("\n"), pos: 0 },
|
|
Token { typ: TokenType::OPEND, value: String::from(";"), pos: 0 },
|
|
Token { typ: TokenType::OPEND, value: String::from("EOF"), pos: 0 }
|
|
];
|
|
let parse_ends: Vec<Token> = vec![
|
|
Token { typ: TokenType::OPEND, value: String::from("EOF"), pos: 0 }
|
|
];
|
|
let out = parse_internal(&input, &op_ends, &parse_ends, &mut 0, ctx);
|
|
return out;
|
|
} |