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");
code += std::str::from_utf8(raw_builtins.as_ref())
.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();
code += &funcs;
@ -50,6 +59,11 @@ fn generate_function(func: Function) -> String {
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
/// Currently used in for statements, to declare local variables
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 {
let mut asm = Assembly::new();
let Program { func, globals } = prog;
let Program {
func,
globals,
structs: _,
} = prog;
asm.add(".intel_syntax noprefix");
asm.add(".text");

2
src/lexer/mod.rs

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

7
src/parser/node_type.rs

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

87
src/parser/rules.rs

@ -23,18 +23,68 @@ use std::convert::TryFrom;
impl Parser {
pub fn parse_program(&mut self) -> Result<Program, String> {
let mut functions = Vec::new();
let mut structs = Vec::new();
let globals = Vec::new();
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 {
func: functions,
structs,
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> {
self.match_token(TokenKind::CurlyBracesOpen)?;
@ -68,7 +118,7 @@ impl Parser {
let arguments: Vec<Variable> = match self.peek()? {
t if t.kind == TokenKind::BraceClose => Vec::new(),
_ => self.parse_arguments()?,
_ => self.parse_typed_variable_list()?,
};
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> {
self.match_token(TokenKind::Colon)?;
let next = self.peek()?;
@ -172,6 +192,9 @@ impl Parser {
}
}
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)),
}
}

Loading…
Cancel
Save