add Stmt::Struct and Expr::New
This commit is contained in:
@@ -117,6 +117,7 @@ impl Analyzer {
|
|||||||
}
|
}
|
||||||
self.functions.insert(name.lexeme.clone(), -1);
|
self.functions.insert(name.lexeme.clone(), -1);
|
||||||
}
|
}
|
||||||
|
Stmt::Struct { name: _, fields: _ } => todo!(),
|
||||||
}
|
}
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
@@ -188,6 +189,7 @@ impl Analyzer {
|
|||||||
Expr::AddrOf { op: _, expr } => {
|
Expr::AddrOf { op: _, expr } => {
|
||||||
self.analyze_expr(expr)?;
|
self.analyze_expr(expr)?;
|
||||||
}
|
}
|
||||||
|
Expr::New(_) => {}
|
||||||
}
|
}
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -6,8 +6,9 @@ use crate::{
|
|||||||
tokenizer::{TokenType, ZernError, error},
|
tokenizer::{TokenType, ZernError, error},
|
||||||
};
|
};
|
||||||
|
|
||||||
pub struct Var {
|
struct Var {
|
||||||
pub stack_offset: usize,
|
pub stack_offset: usize,
|
||||||
|
pub var_type: String,
|
||||||
}
|
}
|
||||||
|
|
||||||
pub struct Env {
|
pub struct Env {
|
||||||
@@ -37,19 +38,20 @@ impl Env {
|
|||||||
self.scopes.pop();
|
self.scopes.pop();
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn define_var(&mut self, name: String, _var_type: String) -> usize {
|
pub fn define_var(&mut self, name: String, var_type: String) -> usize {
|
||||||
let offset = self.next_offset;
|
let offset = self.next_offset;
|
||||||
self.next_offset += 8;
|
self.next_offset += 8;
|
||||||
self.scopes.last_mut().unwrap().insert(
|
self.scopes.last_mut().unwrap().insert(
|
||||||
name,
|
name,
|
||||||
Var {
|
Var {
|
||||||
stack_offset: offset,
|
stack_offset: offset,
|
||||||
|
var_type,
|
||||||
},
|
},
|
||||||
);
|
);
|
||||||
offset
|
offset
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn get_var(&self, name: &str) -> Option<&Var> {
|
fn get_var(&self, name: &str) -> Option<&Var> {
|
||||||
for scope in self.scopes.iter().rev() {
|
for scope in self.scopes.iter().rev() {
|
||||||
if let Some(var) = scope.get(name) {
|
if let Some(var) = scope.get(name) {
|
||||||
return Some(var);
|
return Some(var);
|
||||||
@@ -315,6 +317,9 @@ _builtin_environ:
|
|||||||
Stmt::Extern(name) => {
|
Stmt::Extern(name) => {
|
||||||
emit!(&mut self.output, "extern {}", name.lexeme);
|
emit!(&mut self.output, "extern {}", name.lexeme);
|
||||||
}
|
}
|
||||||
|
Stmt::Struct { name: _, fields: _ } => {
|
||||||
|
// handled in the analyzer
|
||||||
|
}
|
||||||
}
|
}
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
@@ -622,6 +627,7 @@ _builtin_environ:
|
|||||||
return error!(&op.loc, "can only take address of variables and functions");
|
return error!(&op.loc, "can only take address of variables and functions");
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
Expr::New(_) => todo!(),
|
||||||
}
|
}
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -45,6 +45,10 @@ pub enum Stmt {
|
|||||||
Break,
|
Break,
|
||||||
Continue,
|
Continue,
|
||||||
Extern(Token),
|
Extern(Token),
|
||||||
|
Struct {
|
||||||
|
name: Token,
|
||||||
|
fields: Vec<Param>,
|
||||||
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug, Clone)]
|
#[derive(Debug, Clone)]
|
||||||
@@ -84,6 +88,7 @@ pub enum Expr {
|
|||||||
op: Token,
|
op: Token,
|
||||||
expr: Box<Expr>,
|
expr: Box<Expr>,
|
||||||
},
|
},
|
||||||
|
New(Token),
|
||||||
}
|
}
|
||||||
|
|
||||||
// TODO: currently they are all just 64 bit values
|
// TODO: currently they are all just 64 bit values
|
||||||
@@ -127,6 +132,9 @@ impl Parser {
|
|||||||
if self.match_token(&[TokenType::KeywordConst]) {
|
if self.match_token(&[TokenType::KeywordConst]) {
|
||||||
return self.const_declaration();
|
return self.const_declaration();
|
||||||
}
|
}
|
||||||
|
if self.match_token(&[TokenType::KeywordStruct]) {
|
||||||
|
return self.struct_declaration();
|
||||||
|
}
|
||||||
return error!(
|
return error!(
|
||||||
self.peek().loc,
|
self.peek().loc,
|
||||||
"statements not allowed outside function body"
|
"statements not allowed outside function body"
|
||||||
@@ -182,6 +190,29 @@ impl Parser {
|
|||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn struct_declaration(&mut self) -> Result<Stmt, ZernError> {
|
||||||
|
let name = self.consume(TokenType::Identifier, "expected struct name")?;
|
||||||
|
|
||||||
|
self.consume(TokenType::Indent, "expected indent after struct name")?;
|
||||||
|
|
||||||
|
let mut fields = vec![];
|
||||||
|
while !self.eof() && !self.check(&TokenType::Dedent) {
|
||||||
|
let var_name = self.consume(TokenType::Identifier, "expected field name")?;
|
||||||
|
self.consume(TokenType::Colon, "expected ':' after field name")?;
|
||||||
|
|
||||||
|
let var_type = self.consume(TokenType::Identifier, "expected field type")?;
|
||||||
|
if !TYPES.contains(&var_type.lexeme.as_str()) {
|
||||||
|
return error!(&name.loc, format!("unknown type: {}", var_type.lexeme));
|
||||||
|
}
|
||||||
|
|
||||||
|
fields.push(Param { var_type, var_name });
|
||||||
|
}
|
||||||
|
|
||||||
|
self.consume(TokenType::Dedent, "expected dedent after the struct fields")?;
|
||||||
|
|
||||||
|
Ok(Stmt::Struct { name, fields })
|
||||||
|
}
|
||||||
|
|
||||||
fn let_declaration(&mut self) -> Result<Stmt, ZernError> {
|
fn let_declaration(&mut self) -> Result<Stmt, ZernError> {
|
||||||
let name = self.consume(TokenType::Identifier, "expected variable name")?;
|
let name = self.consume(TokenType::Identifier, "expected variable name")?;
|
||||||
|
|
||||||
@@ -524,10 +555,17 @@ impl Parser {
|
|||||||
self.consume(TokenType::RightBracket, "expected ']' after values")?;
|
self.consume(TokenType::RightBracket, "expected ']' after values")?;
|
||||||
|
|
||||||
Ok(Expr::ArrayLiteral(xs))
|
Ok(Expr::ArrayLiteral(xs))
|
||||||
|
} else if self.match_token(&[TokenType::KeywordNew]) {
|
||||||
|
let struct_name =
|
||||||
|
self.consume(TokenType::Identifier, "expected struct name after 'new'")?;
|
||||||
|
Ok(Expr::New(struct_name))
|
||||||
} else if self.match_token(&[TokenType::Identifier]) {
|
} else if self.match_token(&[TokenType::Identifier]) {
|
||||||
Ok(Expr::Variable(self.previous().clone()))
|
Ok(Expr::Variable(self.previous().clone()))
|
||||||
} else {
|
} else {
|
||||||
error!(self.peek().loc, "expected expression")
|
error!(
|
||||||
|
self.peek().loc,
|
||||||
|
format!("expected expression, got '{}'", self.peek().lexeme)
|
||||||
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -52,6 +52,8 @@ pub enum TokenType {
|
|||||||
KeywordContinue,
|
KeywordContinue,
|
||||||
KeywordExtern,
|
KeywordExtern,
|
||||||
KeywordExport,
|
KeywordExport,
|
||||||
|
KeywordStruct,
|
||||||
|
KeywordNew,
|
||||||
|
|
||||||
Indent,
|
Indent,
|
||||||
Dedent,
|
Dedent,
|
||||||
@@ -347,6 +349,8 @@ impl Tokenizer {
|
|||||||
"continue" => TokenType::KeywordContinue,
|
"continue" => TokenType::KeywordContinue,
|
||||||
"extern" => TokenType::KeywordExtern,
|
"extern" => TokenType::KeywordExtern,
|
||||||
"export" => TokenType::KeywordExport,
|
"export" => TokenType::KeywordExport,
|
||||||
|
"struct" => TokenType::KeywordStruct,
|
||||||
|
"new" => TokenType::KeywordNew,
|
||||||
"true" => TokenType::True,
|
"true" => TokenType::True,
|
||||||
"false" => TokenType::False,
|
"false" => TokenType::False,
|
||||||
_ => TokenType::Identifier,
|
_ => TokenType::Identifier,
|
||||||
|
|||||||
Reference in New Issue
Block a user