Browse Source

feat: struct definitions

structs
Garrit Franke 3 years ago
parent
commit
6720631f40
  1. 14
      src/generator/js.rs
  2. 6
      src/generator/x86.rs
  3. 2
      src/lexer/mod.rs
  4. 7
      src/parser/node_type.rs
  5. 87
      src/parser/rules.rs

14
src/generator/js.rs

@ -26,6 +26,15 @@ impl Generator for JsGenerator {
crate::Builtins::get("builtin.js").expect("Could not locate builtin functions"); crate::Builtins::get("builtin.js").expect("Could not locate builtin functions");
code += std::str::from_utf8(raw_builtins.as_ref()) code += std::str::from_utf8(raw_builtins.as_ref())
.expect("Unable to interpret builtin functions"); .expect("Unable to interpret builtin functions");
let structs: String = prog
.structs
.into_iter()
.map(generate_struct_definition)
.collect();
code += &structs;
let funcs: String = prog.func.into_iter().map(generate_function).collect(); let funcs: String = prog.func.into_iter().map(generate_function).collect();
code += &funcs; code += &funcs;
@ -50,6 +59,11 @@ fn generate_function(func: Function) -> String {
raw raw
} }
fn generate_struct_definition(struct_def: StructDef) -> String {
// JS doesn't care about field declaration
format!("class {} {{}}\n", struct_def.name)
}
/// prepend is used to pass optional statements, that will be put in front of the regular block /// prepend is used to pass optional statements, that will be put in front of the regular block
/// Currently used in for statements, to declare local variables /// Currently used in for statements, to declare local variables
fn generate_block(block: Statement, prepend: Option<String>) -> String { fn generate_block(block: Statement, prepend: Option<String>) -> String {

6
src/generator/x86.rs

@ -57,7 +57,11 @@ impl X86Generator {
fn gen_program(&mut self, prog: Program) -> Assembly { fn gen_program(&mut self, prog: Program) -> Assembly {
let mut asm = Assembly::new(); let mut asm = Assembly::new();
let Program { func, globals } = prog; let Program {
func,
globals,
structs: _,
} = prog;
asm.add(".intel_syntax noprefix"); asm.add(".intel_syntax noprefix");
asm.add(".text"); asm.add(".text");

2
src/lexer/mod.rs

@ -141,6 +141,7 @@ pub enum Keyword {
Continue, Continue,
Function, Function,
Boolean, Boolean,
Struct,
Unknown, Unknown,
} }
@ -361,6 +362,7 @@ impl Cursor<'_> {
c if c == "in" => Keyword::In, c if c == "in" => Keyword::In,
c if c == "break" => Keyword::Break, c if c == "break" => Keyword::Break,
c if c == "continue" => Keyword::Continue, c if c == "continue" => Keyword::Continue,
c if c == "struct" => Keyword::Struct,
_ => Keyword::Unknown, _ => Keyword::Unknown,
} }
} }

7
src/parser/node_type.rs

@ -23,6 +23,7 @@ pub type SymbolTable = HashMap<String, Option<Type>>;
#[derive(Debug)] #[derive(Debug)]
pub struct Program { pub struct Program {
pub func: Vec<Function>, pub func: Vec<Function>,
pub structs: Vec<StructDef>,
pub globals: Vec<String>, pub globals: Vec<String>,
} }
@ -51,6 +52,12 @@ pub struct Function {
pub ret_type: Option<Type>, pub ret_type: Option<Type>,
} }
#[derive(Debug, Clone)]
pub struct StructDef {
pub name: String,
pub fields: Vec<Variable>,
}
#[derive(Debug, Eq, PartialEq, Clone)] #[derive(Debug, Eq, PartialEq, Clone)]
pub struct Variable { pub struct Variable {
pub name: String, pub name: String,

87
src/parser/rules.rs

@ -23,18 +23,68 @@ use std::convert::TryFrom;
impl Parser { impl Parser {
pub fn parse_program(&mut self) -> Result<Program, String> { pub fn parse_program(&mut self) -> Result<Program, String> {
let mut functions = Vec::new(); let mut functions = Vec::new();
let mut structs = Vec::new();
let globals = Vec::new(); let globals = Vec::new();
while self.has_more() { while self.has_more() {
functions.push(self.parse_function()?) let next = self.peek()?;
match next.kind {
TokenKind::Keyword(Keyword::Function) => functions.push(self.parse_function()?),
TokenKind::Keyword(Keyword::Struct) => {
structs.push(self.parse_struct_definition()?)
}
_ => return Err(format!("Unexpected token: {}", next.raw)),
}
} }
Ok(Program { Ok(Program {
func: functions, func: functions,
structs,
globals, globals,
}) })
} }
fn parse_struct_definition(&mut self) -> Result<StructDef, String> {
self.match_keyword(Keyword::Struct)?;
let name = self.match_identifier()?;
self.match_token(TokenKind::CurlyBracesOpen)?;
let fields = self.parse_typed_variable_list()?;
self.match_token(TokenKind::CurlyBracesClose)?;
Ok(StructDef { name, fields })
}
fn parse_typed_variable_list(&mut self) -> Result<Vec<Variable>, String> {
let mut args = Vec::new();
// If there is an argument
if let TokenKind::Identifier(_) = self.peek()?.kind {
// Parse first argument
args.push(self.parse_typed_variable()?);
// Then continue to parse arguments
// as long as a comma token is found
while self.peek_token(TokenKind::Comma).is_ok() {
self.match_token(TokenKind::Comma)?;
args.push(self.parse_typed_variable()?);
}
}
Ok(args)
}
fn parse_typed_variable(&mut self) -> Result<Variable, String> {
let next = self.next()?;
if let TokenKind::Identifier(name) = next.kind {
return Ok(Variable {
name,
ty: Some(self.parse_type()?),
});
}
Err(format!("Argument could not be parsed: {}", next.raw))
}
fn parse_block(&mut self) -> Result<Statement, String> { fn parse_block(&mut self) -> Result<Statement, String> {
self.match_token(TokenKind::CurlyBracesOpen)?; self.match_token(TokenKind::CurlyBracesOpen)?;
@ -68,7 +118,7 @@ impl Parser {
let arguments: Vec<Variable> = match self.peek()? { let arguments: Vec<Variable> = match self.peek()? {
t if t.kind == TokenKind::BraceClose => Vec::new(), t if t.kind == TokenKind::BraceClose => Vec::new(),
_ => self.parse_arguments()?, _ => self.parse_typed_variable_list()?,
}; };
self.match_token(TokenKind::BraceClose)?; self.match_token(TokenKind::BraceClose)?;
@ -88,36 +138,6 @@ impl Parser {
}) })
} }
fn parse_arguments(&mut self) -> Result<Vec<Variable>, String> {
let mut args = Vec::new();
// If there is an argument
if let TokenKind::Identifier(_) = self.peek()?.kind {
// Parse first argument
args.push(self.parse_typed_argument_list()?);
// Then continue to parse arguments
// as long as a comma token is found
while self.peek_token(TokenKind::Comma).is_ok() {
self.match_token(TokenKind::Comma)?;
args.push(self.parse_typed_argument_list()?);
}
}
Ok(args)
}
fn parse_typed_argument_list(&mut self) -> Result<Variable, String> {
let next = self.next()?;
if let TokenKind::Identifier(name) = next.kind {
return Ok(Variable {
name,
ty: Some(self.parse_type()?),
});
}
Err(format!("Argument could not be parsed: {}", next.raw))
}
fn parse_type(&mut self) -> Result<Type, String> { fn parse_type(&mut self) -> Result<Type, String> {
self.match_token(TokenKind::Colon)?; self.match_token(TokenKind::Colon)?;
let next = self.peek()?; let next = self.peek()?;
@ -172,6 +192,9 @@ impl Parser {
} }
} }
TokenKind::Literal(_) => Ok(Statement::Exp(self.parse_expression()?)), TokenKind::Literal(_) => Ok(Statement::Exp(self.parse_expression()?)),
TokenKind::Keyword(Keyword::Struct) => {
Err("Struct definitions inside functions are not allowed".to_string())
}
_ => Err(self.make_error(TokenKind::Unknown, token)), _ => Err(self.make_error(TokenKind::Unknown, token)),
} }
} }

Loading…
Cancel
Save