simple enums
This commit is contained in:
@@ -10,6 +10,9 @@ extern sqlite3_column_int
|
|||||||
extern sqlite3_column_text
|
extern sqlite3_column_text
|
||||||
extern sqlite3_finalize
|
extern sqlite3_finalize
|
||||||
|
|
||||||
|
const SQLITE_ROW = 100
|
||||||
|
const SQLITE_DONE = 101
|
||||||
|
|
||||||
func main[] : i64
|
func main[] : i64
|
||||||
rc := 0
|
rc := 0
|
||||||
db := 0
|
db := 0
|
||||||
@@ -38,7 +41,7 @@ func main[] : i64
|
|||||||
io.println("============")
|
io.println("============")
|
||||||
sqlite3_prepare_v2(db, "SELECT * FROM todo", -1, ^stmt, 0)
|
sqlite3_prepare_v2(db, "SELECT * FROM todo", -1, ^stmt, 0)
|
||||||
|
|
||||||
while sqlite3_step(stmt) == 100
|
while sqlite3_step(stmt) == SQLITE_ROW
|
||||||
id := sqlite3_column_int(stmt, 0) as i64
|
id := sqlite3_column_int(stmt, 0) as i64
|
||||||
task := sqlite3_column_text(stmt, 1) as str
|
task := sqlite3_column_text(stmt, 1) as str
|
||||||
io.printf("%d - %s\n", id, task)
|
io.printf("%d - %s\n", id, task)
|
||||||
@@ -50,7 +53,7 @@ func main[] : i64
|
|||||||
|
|
||||||
sqlite3_prepare_v2(db, "INSERT INTO todo(task) VALUES (?);", -1, ^stmt, 0)
|
sqlite3_prepare_v2(db, "INSERT INTO todo(task) VALUES (?);", -1, ^stmt, 0)
|
||||||
sqlite3_bind_text(stmt, 1, task, -1, 0)
|
sqlite3_bind_text(stmt, 1, task, -1, 0)
|
||||||
if sqlite3_step(stmt) != 101
|
if sqlite3_step(stmt) != SQLITE_DONE
|
||||||
panic(sqlite3_errmsg(db))
|
panic(sqlite3_errmsg(db))
|
||||||
|
|
||||||
io.println("\nTask added\n")
|
io.println("\nTask added\n")
|
||||||
@@ -60,7 +63,7 @@ func main[] : i64
|
|||||||
|
|
||||||
sqlite3_prepare_v2(db, "DELETE FROM todo WHERE id = ?;", -1, ^stmt, 0)
|
sqlite3_prepare_v2(db, "DELETE FROM todo WHERE id = ?;", -1, ^stmt, 0)
|
||||||
sqlite3_bind_int(stmt, 1, id, -1, 0)
|
sqlite3_bind_int(stmt, 1, id, -1, 0)
|
||||||
if sqlite3_step(stmt) != 101
|
if sqlite3_step(stmt) != SQLITE_DONE
|
||||||
panic(sqlite3_errmsg(db))
|
panic(sqlite3_errmsg(db))
|
||||||
|
|
||||||
io.println("\nTask deleted\n")
|
io.println("\nTask deleted\n")
|
||||||
|
|||||||
@@ -351,7 +351,8 @@ _builtin_environ:
|
|||||||
if self.emit_debug || *exported || name == "main" {
|
if self.emit_debug || *exported || name == "main" {
|
||||||
emit!(
|
emit!(
|
||||||
&mut self.output,
|
&mut self.output,
|
||||||
"global {name}:function (__end_{name} - {name})",
|
"global {0}:function ({0}.end - {0})",
|
||||||
|
name
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
emit!(&mut self.output, "section .text.{}", name);
|
emit!(&mut self.output, "section .text.{}", name);
|
||||||
@@ -405,9 +406,7 @@ _builtin_environ:
|
|||||||
emit!(&mut self.output, " ret");
|
emit!(&mut self.output, " ret");
|
||||||
}
|
}
|
||||||
|
|
||||||
if self.emit_debug || *exported || name == "main" {
|
emit!(&mut self.output, ".end:");
|
||||||
emit!(&mut self.output, "__end_{}:", name);
|
|
||||||
}
|
|
||||||
|
|
||||||
// patch the stack size after we know how much we actually need
|
// patch the stack size after we know how much we actually need
|
||||||
let patch = format!(" sub rsp, {:<10}", (env.next_offset + 15) & !15);
|
let patch = format!(" sub rsp, {:<10}", (env.next_offset + 15) & !15);
|
||||||
@@ -481,7 +480,10 @@ _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: _ } => {
|
Stmt::Struct { .. } => {
|
||||||
|
// handled in SymbolTable
|
||||||
|
}
|
||||||
|
Stmt::Enum { .. } => {
|
||||||
// handled in SymbolTable
|
// handled in SymbolTable
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -77,6 +77,10 @@ pub enum Stmt {
|
|||||||
name: Token,
|
name: Token,
|
||||||
fields: Vec<Param>,
|
fields: Vec<Param>,
|
||||||
},
|
},
|
||||||
|
Enum {
|
||||||
|
name: Token,
|
||||||
|
variants: Vec<Token>,
|
||||||
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
pub static NEXT_EXPR_ID: AtomicUsize = AtomicUsize::new(0);
|
pub static NEXT_EXPR_ID: AtomicUsize = AtomicUsize::new(0);
|
||||||
@@ -191,6 +195,9 @@ impl Parser {
|
|||||||
if self.match_token(&[TokenType::KeywordStruct]) {
|
if self.match_token(&[TokenType::KeywordStruct]) {
|
||||||
return self.struct_declaration();
|
return self.struct_declaration();
|
||||||
}
|
}
|
||||||
|
if self.match_token(&[TokenType::KeywordEnum]) {
|
||||||
|
return self.enum_declaration();
|
||||||
|
}
|
||||||
return error!(
|
return error!(
|
||||||
self.peek().loc,
|
self.peek().loc,
|
||||||
"statements not allowed outside function body"
|
"statements not allowed outside function body"
|
||||||
@@ -269,11 +276,26 @@ impl Parser {
|
|||||||
fields.push(Param { var_type, var_name });
|
fields.push(Param { var_type, var_name });
|
||||||
}
|
}
|
||||||
|
|
||||||
self.consume(TokenType::Dedent, "expected dedent after the struct fields")?;
|
self.consume(TokenType::Dedent, "expected dedent after struct fields")?;
|
||||||
|
|
||||||
Ok(Stmt::Struct { name, fields })
|
Ok(Stmt::Struct { name, fields })
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn enum_declaration(&mut self) -> Result<Stmt, ZernError> {
|
||||||
|
let name = self.consume(TokenType::Identifier, "expected enum name")?;
|
||||||
|
|
||||||
|
self.consume(TokenType::Indent, "expected indent after enum name")?;
|
||||||
|
|
||||||
|
let mut variants = vec![];
|
||||||
|
while !self.eof() && !self.check(&TokenType::Dedent) {
|
||||||
|
variants.push(self.consume(TokenType::Identifier, "expected variant name")?);
|
||||||
|
}
|
||||||
|
|
||||||
|
self.consume(TokenType::Dedent, "expected dedent after enum variants")?;
|
||||||
|
|
||||||
|
Ok(Stmt::Enum { name, variants })
|
||||||
|
}
|
||||||
|
|
||||||
fn const_declaration(&mut self) -> Result<Stmt, ZernError> {
|
fn const_declaration(&mut self) -> Result<Stmt, ZernError> {
|
||||||
let name = self.consume(TokenType::Identifier, "expected const name")?;
|
let name = self.consume(TokenType::Identifier, "expected const name")?;
|
||||||
self.consume(TokenType::Equal, "expected '=' after const name")?;
|
self.consume(TokenType::Equal, "expected '=' after const name")?;
|
||||||
|
|||||||
@@ -140,6 +140,16 @@ impl SymbolTable {
|
|||||||
|
|
||||||
self.structs.insert(name.lexeme.clone(), fields_map);
|
self.structs.insert(name.lexeme.clone(), fields_map);
|
||||||
}
|
}
|
||||||
|
Stmt::Enum { name, variants } => {
|
||||||
|
// TODO: distinct enum types
|
||||||
|
for (i, v) in variants.iter().enumerate() {
|
||||||
|
let variant = format!("{}.{}", name.lexeme, v.lexeme);
|
||||||
|
if self.is_name_defined(&variant) {
|
||||||
|
return error!(name.loc, format!("tried to redefine '{}'", variant));
|
||||||
|
}
|
||||||
|
self.constants.insert(variant, i as i64);
|
||||||
|
}
|
||||||
|
}
|
||||||
_ => {}
|
_ => {}
|
||||||
}
|
}
|
||||||
Ok(())
|
Ok(())
|
||||||
|
|||||||
@@ -57,6 +57,7 @@ pub enum TokenType {
|
|||||||
KeywordStruct,
|
KeywordStruct,
|
||||||
KeywordNew,
|
KeywordNew,
|
||||||
KeywordAs,
|
KeywordAs,
|
||||||
|
KeywordEnum,
|
||||||
|
|
||||||
Indent,
|
Indent,
|
||||||
Dedent,
|
Dedent,
|
||||||
@@ -376,6 +377,7 @@ impl Tokenizer {
|
|||||||
"struct" => TokenType::KeywordStruct,
|
"struct" => TokenType::KeywordStruct,
|
||||||
"new" => TokenType::KeywordNew,
|
"new" => TokenType::KeywordNew,
|
||||||
"as" => TokenType::KeywordAs,
|
"as" => TokenType::KeywordAs,
|
||||||
|
"enum" => TokenType::KeywordEnum,
|
||||||
"true" => TokenType::True,
|
"true" => TokenType::True,
|
||||||
"false" => TokenType::False,
|
"false" => TokenType::False,
|
||||||
_ => TokenType::Identifier,
|
_ => TokenType::Identifier,
|
||||||
|
|||||||
@@ -355,6 +355,7 @@ impl<'a> TypeChecker<'a> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
Stmt::Enum { .. } => {}
|
||||||
}
|
}
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|||||||
2
test.zr
2
test.zr
@@ -31,6 +31,7 @@ func run_test[x: str] : void
|
|||||||
run_start_time := os.time()
|
run_start_time := os.time()
|
||||||
~status, ok := os.run_shell_command(run_cmd)
|
~status, ok := os.run_shell_command(run_cmd)
|
||||||
if !ok || status != 0
|
if !ok || status != 0
|
||||||
|
io.println("Test failed.")
|
||||||
os.exit(1)
|
os.exit(1)
|
||||||
run_end_time := os.time()
|
run_end_time := os.time()
|
||||||
|
|
||||||
@@ -50,3 +51,4 @@ func main[] : i64
|
|||||||
|
|
||||||
run_directory("examples/")
|
run_directory("examples/")
|
||||||
run_directory("examples/euler/")
|
run_directory("examples/euler/")
|
||||||
|
io.println("DONE")
|
||||||
|
|||||||
Reference in New Issue
Block a user