turn Assign into a statement
This commit is contained in:
@@ -290,7 +290,7 @@ func main[argc: i64, argv: ptr] : i64
|
||||
|
||||
c := chip8_create()
|
||||
|
||||
buffer : io.Buffer = must(io.read_binary_file?(path))
|
||||
buffer : Blob = must(io.read_binary_file?(path))
|
||||
|
||||
for i in 0..buffer->size
|
||||
c->memory[0x200 + i] = buffer->data[i]
|
||||
|
||||
@@ -236,6 +236,45 @@ _builtin_environ:
|
||||
let offset = env.define_var(name.lexeme.clone(), var_type);
|
||||
emit!(&mut self.output, " mov QWORD [rbp-{}], rax", offset);
|
||||
}
|
||||
Stmt::Assign { left, op, value } => {
|
||||
self.compile_expr(env, value)?;
|
||||
|
||||
match &left.kind {
|
||||
ExprKind::Variable(name) => {
|
||||
// already ensured by the typechecker
|
||||
let var = env.get_var(&name.lexeme).unwrap();
|
||||
emit!(
|
||||
&mut self.output,
|
||||
" mov QWORD [rbp-{}], rax",
|
||||
var.stack_offset,
|
||||
);
|
||||
}
|
||||
ExprKind::Index {
|
||||
expr,
|
||||
bracket: _,
|
||||
index,
|
||||
} => {
|
||||
emit!(&mut self.output, " push rax");
|
||||
self.compile_expr(env, expr)?;
|
||||
emit!(&mut self.output, " push rax");
|
||||
self.compile_expr(env, index)?;
|
||||
emit!(&mut self.output, " pop rbx");
|
||||
emit!(&mut self.output, " add rbx, rax");
|
||||
emit!(&mut self.output, " pop rax");
|
||||
emit!(&mut self.output, " mov BYTE [rbx], al");
|
||||
}
|
||||
ExprKind::MemberAccess { left, field } => {
|
||||
emit!(&mut self.output, " push rax");
|
||||
|
||||
let offset = self.get_field_offset(left, field)?;
|
||||
|
||||
self.compile_expr(env, left)?;
|
||||
emit!(&mut self.output, " pop rbx");
|
||||
emit!(&mut self.output, " mov QWORD [rax+{}], rbx", offset);
|
||||
}
|
||||
_ => return error!(&op.loc, "invalid assignment target"),
|
||||
};
|
||||
}
|
||||
Stmt::Const { name: _, value: _ } => {
|
||||
// handled in SymbolTable
|
||||
}
|
||||
@@ -573,45 +612,6 @@ _builtin_environ:
|
||||
);
|
||||
}
|
||||
}
|
||||
ExprKind::Assign { left, op, value } => {
|
||||
self.compile_expr(env, value)?;
|
||||
|
||||
match &left.kind {
|
||||
ExprKind::Variable(name) => {
|
||||
// already ensured by the typechecker
|
||||
let var = env.get_var(&name.lexeme).unwrap();
|
||||
emit!(
|
||||
&mut self.output,
|
||||
" mov QWORD [rbp-{}], rax",
|
||||
var.stack_offset,
|
||||
);
|
||||
}
|
||||
ExprKind::Index {
|
||||
expr,
|
||||
bracket: _,
|
||||
index,
|
||||
} => {
|
||||
emit!(&mut self.output, " push rax");
|
||||
self.compile_expr(env, expr)?;
|
||||
emit!(&mut self.output, " push rax");
|
||||
self.compile_expr(env, index)?;
|
||||
emit!(&mut self.output, " pop rbx");
|
||||
emit!(&mut self.output, " add rbx, rax");
|
||||
emit!(&mut self.output, " pop rax");
|
||||
emit!(&mut self.output, " mov BYTE [rbx], al");
|
||||
}
|
||||
ExprKind::MemberAccess { left, field } => {
|
||||
emit!(&mut self.output, " push rax");
|
||||
|
||||
let offset = self.get_field_offset(left, field)?;
|
||||
|
||||
self.compile_expr(env, left)?;
|
||||
emit!(&mut self.output, " pop rbx");
|
||||
emit!(&mut self.output, " mov QWORD [rax+{}], rbx", offset);
|
||||
}
|
||||
_ => return error!(&op.loc, "invalid assignment target"),
|
||||
};
|
||||
}
|
||||
ExprKind::Call {
|
||||
callee,
|
||||
paren: _,
|
||||
|
||||
@@ -22,6 +22,11 @@ pub enum Stmt {
|
||||
var_type: Option<Token>,
|
||||
initializer: Expr,
|
||||
},
|
||||
Assign {
|
||||
left: Expr,
|
||||
op: Token,
|
||||
value: Expr,
|
||||
},
|
||||
Const {
|
||||
name: Token,
|
||||
value: Token,
|
||||
@@ -101,11 +106,6 @@ pub enum ExprKind {
|
||||
right: Box<Expr>,
|
||||
},
|
||||
Variable(Token),
|
||||
Assign {
|
||||
left: Box<Expr>,
|
||||
op: Token,
|
||||
value: Box<Expr>,
|
||||
},
|
||||
Call {
|
||||
callee: Box<Expr>,
|
||||
paren: Token,
|
||||
@@ -312,7 +312,18 @@ impl Parser {
|
||||
} else if self.match_token(&[TokenType::KeywordContinue]) {
|
||||
Ok(Stmt::Continue)
|
||||
} else {
|
||||
Ok(Stmt::Expression(self.expression()?))
|
||||
let expr = self.expression()?;
|
||||
if self.match_token(&[TokenType::Equal]) {
|
||||
let op = self.previous().clone();
|
||||
let value = self.expression()?;
|
||||
Ok(Stmt::Assign {
|
||||
left: expr,
|
||||
op,
|
||||
value,
|
||||
})
|
||||
} else {
|
||||
Ok(Stmt::Expression(expr))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -365,24 +376,7 @@ impl Parser {
|
||||
}
|
||||
|
||||
fn expression(&mut self) -> Result<Expr, ZernError> {
|
||||
self.assignment()
|
||||
}
|
||||
|
||||
fn assignment(&mut self) -> Result<Expr, ZernError> {
|
||||
let expr = self.pipe()?;
|
||||
|
||||
if self.match_token(&[TokenType::Equal]) {
|
||||
let equals = self.previous().clone();
|
||||
let value = self.assignment()?;
|
||||
|
||||
return Ok(Expr::new(ExprKind::Assign {
|
||||
left: Box::new(expr),
|
||||
op: equals,
|
||||
value: Box::new(value),
|
||||
}));
|
||||
}
|
||||
|
||||
Ok(expr)
|
||||
self.pipe()
|
||||
}
|
||||
|
||||
fn pipe(&mut self) -> Result<Expr, ZernError> {
|
||||
|
||||
@@ -156,9 +156,9 @@ const DNS_TYPE_A = 1
|
||||
const DNS_CLASS_IN = 1
|
||||
const DNS_RECURSION_DESIRED = 256
|
||||
|
||||
func net.encode_dns_name[domain: str] : io.Buffer
|
||||
func net.encode_dns_name[domain: str] : Blob
|
||||
domain_len := str.len(domain)
|
||||
buf : io.Buffer = must(io.Buffer.alloc?(domain_len + 2))
|
||||
buf : Blob = must(Blob.alloc?(domain_len + 2))
|
||||
out_pos := 0
|
||||
part_start := 0
|
||||
i := 0
|
||||
@@ -175,9 +175,9 @@ func net.encode_dns_name[domain: str] : io.Buffer
|
||||
buf->data[out_pos] = 0
|
||||
return buf
|
||||
|
||||
func net.build_dns_query[domain_name: str, record_type: i64] : io.Buffer
|
||||
func net.build_dns_query[domain_name: str, record_type: i64] : Blob
|
||||
name := net.encode_dns_name(domain_name)
|
||||
out : io.Buffer = must(io.Buffer.alloc?(12 + name->size + 4))
|
||||
out : Blob = must(Blob.alloc?(12 + name->size + 4))
|
||||
|
||||
// header
|
||||
id := math.abs(os.urandom_i64() % 65536)
|
||||
@@ -193,7 +193,7 @@ func net.build_dns_query[domain_name: str, record_type: i64] : io.Buffer
|
||||
mem.write16be(out->data + 12 + name->size, record_type)
|
||||
mem.write16be(out->data + 12 + name->size + 2, DNS_CLASS_IN)
|
||||
|
||||
io.Buffer.free(name)
|
||||
Blob.free(name)
|
||||
return out
|
||||
|
||||
// TODO: dont resolve if its already an IP
|
||||
@@ -207,7 +207,7 @@ func net.resolve?[domain: str] : i64
|
||||
return -1
|
||||
|
||||
net.udp_send_to(s, s->addr, query->data, query->size)
|
||||
io.Buffer.free(query)
|
||||
Blob.free(query)
|
||||
pkt := net.udp_receive(s, 1024)
|
||||
net.UDPSocket.close_and_free(s)
|
||||
|
||||
|
||||
@@ -333,21 +333,21 @@ func io.read_line[]: str
|
||||
buffer = must(mem.realloc?(buffer as ptr, n + 1))
|
||||
return buffer
|
||||
|
||||
struct io.Buffer
|
||||
struct Blob
|
||||
data: ptr
|
||||
size: i64
|
||||
|
||||
func io.Buffer.alloc?[size: i64] : io.Buffer
|
||||
func Blob.alloc?[size: i64] : Blob
|
||||
err.clear()
|
||||
buffer := new* io.Buffer
|
||||
buffer := new* Blob
|
||||
buffer->size = size
|
||||
buffer->data = mem.alloc?(size)
|
||||
if err.check()
|
||||
mem.free(buffer)
|
||||
return 0 as io.Buffer
|
||||
return 0 as Blob
|
||||
return buffer
|
||||
|
||||
func io.Buffer.free[buf: io.Buffer] : void
|
||||
func Blob.free[buf: Blob] : void
|
||||
mem.free(buf->data)
|
||||
mem.free(buf)
|
||||
|
||||
@@ -396,30 +396,30 @@ func io.read_text_file?[path: str] : str
|
||||
buffer[n] = 0
|
||||
return buffer
|
||||
|
||||
func io.read_binary_file?[path: str] : io.Buffer
|
||||
func io.read_binary_file?[path: str] : Blob
|
||||
err.clear()
|
||||
fd := _builtin_syscall(SYS_openat, -100, path, 0, 0)
|
||||
if fd < 0
|
||||
err.set(ERR_OPEN_FAILED, "io.read_binary_file?: failed to open file")
|
||||
return 0 as io.Buffer
|
||||
return 0 as Blob
|
||||
|
||||
buf := new* io.Buffer
|
||||
buf := new* Blob
|
||||
buf->size = _builtin_syscall(SYS_lseek, fd, 0, 2)
|
||||
_builtin_syscall(SYS_lseek, fd, 0, 0)
|
||||
|
||||
buf->data = mem.alloc?(buf->size)
|
||||
if err.check()
|
||||
io.Buffer.free(buf)
|
||||
Blob.free(buf)
|
||||
_builtin_syscall(SYS_close, fd)
|
||||
return 0 as io.Buffer
|
||||
return 0 as Blob
|
||||
|
||||
n := _builtin_syscall(SYS_read, fd, buf->data, buf->size)
|
||||
_builtin_syscall(SYS_close, fd)
|
||||
|
||||
if n != buf->size
|
||||
io.Buffer.free(buf)
|
||||
Blob.free(buf)
|
||||
err.set(ERR_READ_FAILED, "io.read_binary_file?: failed to read file")
|
||||
return 0 as io.Buffer
|
||||
return 0 as Blob
|
||||
|
||||
return buf
|
||||
|
||||
|
||||
@@ -111,6 +111,59 @@ impl<'a> TypeChecker<'a> {
|
||||
|
||||
env.define_var(name.lexeme.clone(), actual_type);
|
||||
}
|
||||
Stmt::Assign { left, op, value } => {
|
||||
let value_type = self.typecheck_expr(env, value)?;
|
||||
|
||||
match &left.kind {
|
||||
ExprKind::Variable(name) => {
|
||||
let existing_var_type = match env.get_var_type(&name.lexeme) {
|
||||
Some(x) => x,
|
||||
None => {
|
||||
return error!(
|
||||
name.loc,
|
||||
format!("undefined variable: {}", &name.lexeme)
|
||||
);
|
||||
}
|
||||
};
|
||||
expect_type!(value_type.clone(), *existing_var_type, name.loc);
|
||||
}
|
||||
ExprKind::Index {
|
||||
expr,
|
||||
bracket,
|
||||
index,
|
||||
} => {
|
||||
expect_types!(self.typecheck_expr(env, expr)?, ["ptr", "str"], bracket.loc);
|
||||
expect_types!(self.typecheck_expr(env, index)?, ["i64", "u8"], bracket.loc);
|
||||
expect_types!(value_type.clone(), ["u8", "i64"], bracket.loc);
|
||||
}
|
||||
ExprKind::MemberAccess { left, field } => {
|
||||
let left_type = self.typecheck_expr(env, left)?;
|
||||
|
||||
let fields = match self.symbol_table.structs.get(&left_type) {
|
||||
Some(f) => f,
|
||||
None => {
|
||||
return error!(
|
||||
&field.loc,
|
||||
format!("unknown struct type: {}", left_type)
|
||||
);
|
||||
}
|
||||
};
|
||||
|
||||
let f = match fields.get(&field.lexeme) {
|
||||
Some(o) => o,
|
||||
None => {
|
||||
return error!(
|
||||
&field.loc,
|
||||
format!("unknown field: {}", &field.lexeme)
|
||||
);
|
||||
}
|
||||
};
|
||||
|
||||
expect_type!(value_type.clone(), f.field_type, field.loc);
|
||||
}
|
||||
_ => return error!(&op.loc, "invalid assignment target"),
|
||||
}
|
||||
}
|
||||
Stmt::Const { name: _, value: _ } => {
|
||||
// handled in SymbolTable
|
||||
}
|
||||
@@ -354,60 +407,6 @@ impl<'a> TypeChecker<'a> {
|
||||
}
|
||||
}
|
||||
}
|
||||
ExprKind::Assign { left, op, value } => {
|
||||
let value_type = self.typecheck_expr(env, value)?;
|
||||
|
||||
match &left.kind {
|
||||
ExprKind::Variable(name) => {
|
||||
let existing_var_type = match env.get_var_type(&name.lexeme) {
|
||||
Some(x) => x,
|
||||
None => {
|
||||
return error!(
|
||||
name.loc,
|
||||
format!("undefined variable: {}", &name.lexeme)
|
||||
);
|
||||
}
|
||||
};
|
||||
expect_type!(value_type.clone(), *existing_var_type, name.loc);
|
||||
}
|
||||
ExprKind::Index {
|
||||
expr,
|
||||
bracket,
|
||||
index,
|
||||
} => {
|
||||
expect_types!(self.typecheck_expr(env, expr)?, ["ptr", "str"], bracket.loc);
|
||||
expect_types!(self.typecheck_expr(env, index)?, ["i64", "u8"], bracket.loc);
|
||||
expect_types!(value_type.clone(), ["u8", "i64"], bracket.loc);
|
||||
}
|
||||
ExprKind::MemberAccess { left, field } => {
|
||||
let left_type = self.typecheck_expr(env, left)?;
|
||||
|
||||
let fields = match self.symbol_table.structs.get(&left_type) {
|
||||
Some(f) => f,
|
||||
None => {
|
||||
return error!(
|
||||
&field.loc,
|
||||
format!("unknown struct type: {}", left_type)
|
||||
);
|
||||
}
|
||||
};
|
||||
|
||||
let f = match fields.get(&field.lexeme) {
|
||||
Some(o) => o,
|
||||
None => {
|
||||
return error!(
|
||||
&field.loc,
|
||||
format!("unknown field: {}", &field.lexeme)
|
||||
);
|
||||
}
|
||||
};
|
||||
|
||||
expect_type!(value_type.clone(), f.field_type, field.loc);
|
||||
}
|
||||
_ => return error!(&op.loc, "invalid assignment target"),
|
||||
}
|
||||
Ok(value_type)
|
||||
}
|
||||
ExprKind::Call {
|
||||
callee,
|
||||
paren,
|
||||
|
||||
Reference in New Issue
Block a user