basic global constants
This commit is contained in:
@@ -7,12 +7,14 @@ use crate::{
|
|||||||
|
|
||||||
pub struct Analyzer {
|
pub struct Analyzer {
|
||||||
pub functions: HashMap<String, i32>,
|
pub functions: HashMap<String, i32>,
|
||||||
|
pub constants: HashMap<String, u64>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Analyzer {
|
impl Analyzer {
|
||||||
pub fn new() -> Analyzer {
|
pub fn new() -> Analyzer {
|
||||||
Analyzer {
|
Analyzer {
|
||||||
functions: HashMap::new(),
|
functions: HashMap::new(),
|
||||||
|
constants: HashMap::new(),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -44,6 +46,18 @@ impl Analyzer {
|
|||||||
} => {
|
} => {
|
||||||
self.analyze_expr(initializer)?;
|
self.analyze_expr(initializer)?;
|
||||||
}
|
}
|
||||||
|
Stmt::Const { name, value } => {
|
||||||
|
if self.constants.contains_key(&name.lexeme)
|
||||||
|
|| self.functions.contains_key(&name.lexeme)
|
||||||
|
{
|
||||||
|
return error!(
|
||||||
|
name.loc,
|
||||||
|
format!("tried to redefine constant '{}'", name.lexeme)
|
||||||
|
);
|
||||||
|
}
|
||||||
|
self.constants
|
||||||
|
.insert(name.lexeme.clone(), value.lexeme.parse().unwrap());
|
||||||
|
}
|
||||||
Stmt::Block(statements) => {
|
Stmt::Block(statements) => {
|
||||||
for stmt in statements {
|
for stmt in statements {
|
||||||
self.analyze_stmt(stmt)?;
|
self.analyze_stmt(stmt)?;
|
||||||
|
|||||||
@@ -176,6 +176,9 @@ _builtin_environ:
|
|||||||
let offset = env.define_var(name.lexeme.clone(), var_type);
|
let offset = env.define_var(name.lexeme.clone(), var_type);
|
||||||
emit!(&mut self.output, " mov QWORD [rbp-{}], rax", offset);
|
emit!(&mut self.output, " mov QWORD [rbp-{}], rax", offset);
|
||||||
}
|
}
|
||||||
|
Stmt::Const { name: _, value: _ } => {
|
||||||
|
// handled in the analyzer
|
||||||
|
}
|
||||||
Stmt::Block(statements) => {
|
Stmt::Block(statements) => {
|
||||||
env.push_scope();
|
env.push_scope();
|
||||||
for stmt in statements {
|
for stmt in statements {
|
||||||
@@ -445,18 +448,29 @@ _builtin_environ:
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
Expr::Variable(name) => {
|
Expr::Variable(name) => {
|
||||||
// TODO: move to analyzer
|
if self.analyzer.constants.contains_key(&name.lexeme) {
|
||||||
let var = match env.get_var(&name.lexeme) {
|
emit!(
|
||||||
Some(x) => x,
|
&mut self.output,
|
||||||
None => {
|
" mov rax, {}",
|
||||||
return error!(name.loc, format!("undefined variable: {}", &name.lexeme));
|
self.analyzer.constants[&name.lexeme]
|
||||||
}
|
);
|
||||||
};
|
} else {
|
||||||
emit!(
|
// TODO: move to analyzer
|
||||||
&mut self.output,
|
let var = match env.get_var(&name.lexeme) {
|
||||||
" mov rax, QWORD [rbp-{}]",
|
Some(x) => x,
|
||||||
var.stack_offset,
|
None => {
|
||||||
);
|
return error!(
|
||||||
|
name.loc,
|
||||||
|
format!("undefined variable: {}", &name.lexeme)
|
||||||
|
);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
emit!(
|
||||||
|
&mut self.output,
|
||||||
|
" mov rax, QWORD [rbp-{}]",
|
||||||
|
var.stack_offset,
|
||||||
|
);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
Expr::Assign { name, value } => {
|
Expr::Assign { name, value } => {
|
||||||
self.compile_expr(env, *value)?;
|
self.compile_expr(env, *value)?;
|
||||||
|
|||||||
@@ -33,6 +33,7 @@ fn compile_file_to(
|
|||||||
}
|
}
|
||||||
|
|
||||||
for stmt in statements {
|
for stmt in statements {
|
||||||
|
// top level statements are all function/const/extern declarations so a new env for each
|
||||||
codegen.compile_stmt(&mut codegen_x86_64::Env::new(), stmt)?;
|
codegen.compile_stmt(&mut codegen_x86_64::Env::new(), stmt)?;
|
||||||
}
|
}
|
||||||
Ok(())
|
Ok(())
|
||||||
|
|||||||
@@ -14,6 +14,10 @@ pub enum Stmt {
|
|||||||
var_type: Option<Token>,
|
var_type: Option<Token>,
|
||||||
initializer: Expr,
|
initializer: Expr,
|
||||||
},
|
},
|
||||||
|
Const {
|
||||||
|
name: Token,
|
||||||
|
value: Token,
|
||||||
|
},
|
||||||
Block(Vec<Stmt>),
|
Block(Vec<Stmt>),
|
||||||
If {
|
If {
|
||||||
condition: Expr,
|
condition: Expr,
|
||||||
@@ -115,6 +119,9 @@ impl Parser {
|
|||||||
if self.match_token(&[TokenType::KeywordExtern]) {
|
if self.match_token(&[TokenType::KeywordExtern]) {
|
||||||
return self.extern_declaration();
|
return self.extern_declaration();
|
||||||
}
|
}
|
||||||
|
if self.match_token(&[TokenType::KeywordConst]) {
|
||||||
|
return self.const_declaration();
|
||||||
|
}
|
||||||
return error!(
|
return error!(
|
||||||
self.peek().loc,
|
self.peek().loc,
|
||||||
"statements not allowed outside function body"
|
"statements not allowed outside function body"
|
||||||
@@ -192,6 +199,13 @@ impl Parser {
|
|||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn const_declaration(&mut self) -> Result<Stmt, ZernError> {
|
||||||
|
let name = self.consume(TokenType::Identifier, "expected const name")?;
|
||||||
|
self.consume(TokenType::Equal, "expected '=' after const name")?;
|
||||||
|
let value = self.consume(TokenType::Number, "expected a number after '='")?;
|
||||||
|
Ok(Stmt::Const { name, value })
|
||||||
|
}
|
||||||
|
|
||||||
fn extern_declaration(&mut self) -> Result<Stmt, ZernError> {
|
fn extern_declaration(&mut self) -> Result<Stmt, ZernError> {
|
||||||
Ok(Stmt::Extern(
|
Ok(Stmt::Extern(
|
||||||
self.consume(TokenType::Identifier, "expected extern name")?,
|
self.consume(TokenType::Identifier, "expected extern name")?,
|
||||||
|
|||||||
@@ -39,6 +39,7 @@ pub enum TokenType {
|
|||||||
False,
|
False,
|
||||||
|
|
||||||
KeywordLet,
|
KeywordLet,
|
||||||
|
KeywordConst,
|
||||||
KeywordIf,
|
KeywordIf,
|
||||||
KeywordElse,
|
KeywordElse,
|
||||||
KeywordWhile,
|
KeywordWhile,
|
||||||
@@ -336,6 +337,7 @@ impl Tokenizer {
|
|||||||
let lexeme: String = self.source[self.start..self.current].iter().collect();
|
let lexeme: String = self.source[self.start..self.current].iter().collect();
|
||||||
self.add_token(match lexeme.as_str() {
|
self.add_token(match lexeme.as_str() {
|
||||||
"let" => TokenType::KeywordLet,
|
"let" => TokenType::KeywordLet,
|
||||||
|
"const" => TokenType::KeywordConst,
|
||||||
"if" => TokenType::KeywordIf,
|
"if" => TokenType::KeywordIf,
|
||||||
"else" => TokenType::KeywordElse,
|
"else" => TokenType::KeywordElse,
|
||||||
"while" => TokenType::KeywordWhile,
|
"while" => TokenType::KeywordWhile,
|
||||||
|
|||||||
Reference in New Issue
Block a user