Compare commits
No commits in common. "7def9abc5ab97df661933d292b3c73b60d70f844" and "3f9408247767769c16c951bc433fe74affa015a0" have entirely different histories.
7def9abc5a
...
3f94082477
5 changed files with 8 additions and 116 deletions
|
@ -42,10 +42,6 @@ fn multwo(num: i32, double_flag: bool) i32 {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn multwo_with_one(b: i32) i32 {
|
|
||||||
return multwo(b, false) + b;
|
|
||||||
}
|
|
||||||
|
|
||||||
fn add(a: i32, b: i32) i32 {
|
fn add(a: i32, b: i32) i32 {
|
||||||
return 69 + 69;
|
return 69 + 69;
|
||||||
}
|
}
|
||||||
|
|
|
@ -186,8 +186,6 @@ pub const TypeSolver = struct {
|
||||||
|
|
||||||
// TODO make return type optional and so, skip exprs that
|
// TODO make return type optional and so, skip exprs that
|
||||||
// fail to be fully resolved, instead of returning CompileError
|
// fail to be fully resolved, instead of returning CompileError
|
||||||
|
|
||||||
// TODO make the expr ptr a const since we want to implicit cast things
|
|
||||||
pub fn resolveExprType(
|
pub fn resolveExprType(
|
||||||
self: *@This(),
|
self: *@This(),
|
||||||
ctx: *comp.CompilationContext,
|
ctx: *comp.CompilationContext,
|
||||||
|
@ -202,6 +200,7 @@ pub const TypeSolver = struct {
|
||||||
// all numeric operations return numeric types
|
// all numeric operations return numeric types
|
||||||
.Add, .Sub, .Mul, .Div, .Mod => left_type,
|
.Add, .Sub, .Mul, .Div, .Mod => left_type,
|
||||||
|
|
||||||
|
// TODO check left and right as numeric
|
||||||
.Greater, .GreaterEqual, .Less, .LessEqual => blk: {
|
.Greater, .GreaterEqual, .Less, .LessEqual => blk: {
|
||||||
try self.expectSymUnTypeNumeric(left_type);
|
try self.expectSymUnTypeNumeric(left_type);
|
||||||
try self.expectSymUnTypeNumeric(right_type);
|
try self.expectSymUnTypeNumeric(right_type);
|
||||||
|
@ -227,8 +226,7 @@ pub const TypeSolver = struct {
|
||||||
return switch (literal) {
|
return switch (literal) {
|
||||||
.Bool => SymbolUnderlyingType{ .Bool = {} },
|
.Bool => SymbolUnderlyingType{ .Bool = {} },
|
||||||
|
|
||||||
// TODO recast Integer32 as Integer64 if the type we're
|
// TODO determine its i64 depending of parseInt results
|
||||||
// checking into is Integer64, but not the other way.
|
|
||||||
.Integer32 => SymbolUnderlyingType{ .Integer32 = {} },
|
.Integer32 => SymbolUnderlyingType{ .Integer32 = {} },
|
||||||
.Integer64 => SymbolUnderlyingType{ .Integer64 = {} },
|
.Integer64 => SymbolUnderlyingType{ .Integer64 = {} },
|
||||||
.Float => SymbolUnderlyingType{ .Double = {} },
|
.Float => SymbolUnderlyingType{ .Double = {} },
|
||||||
|
@ -258,31 +256,13 @@ pub const TypeSolver = struct {
|
||||||
var symbol = try ctx.fetchGlobalSymbol(func_name, .Function);
|
var symbol = try ctx.fetchGlobalSymbol(func_name, .Function);
|
||||||
var func_sym = symbol.Function;
|
var func_sym = symbol.Function;
|
||||||
|
|
||||||
for (call.arguments.toSlice()) |arg_expr, idx| {
|
// TODO check parameter type mismatches between
|
||||||
var param_type = func_sym.parameter_list.at(idx);
|
// call.arguments and func_sym.parameters
|
||||||
var arg_type = try self.resolveExprType(ctx, &arg_expr);
|
|
||||||
|
|
||||||
self.expectSymUnTypeEqual(arg_type, param_type) catch {
|
|
||||||
self.doError(
|
|
||||||
"Expected parameter {} to be {}, got {}",
|
|
||||||
idx,
|
|
||||||
@tagName(comp.SymbolUnderlyingTypeEnum(param_type)),
|
|
||||||
@tagName(comp.SymbolUnderlyingTypeEnum(arg_type)),
|
|
||||||
);
|
|
||||||
|
|
||||||
return CompileError.TypeError;
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
return func_sym.return_type;
|
return func_sym.return_type;
|
||||||
},
|
},
|
||||||
|
|
||||||
.Variable => |vari| {
|
// TODO analysis for .Variable
|
||||||
self.setErrToken(vari);
|
|
||||||
var metadata = try ctx.resolveVarType(vari.lexeme);
|
|
||||||
try ctx.insertMetadata(expr, metadata);
|
|
||||||
return metadata.typ;
|
|
||||||
},
|
|
||||||
|
|
||||||
.Get => |get| {
|
.Get => |get| {
|
||||||
var target = get.target.*;
|
var target = get.target.*;
|
||||||
|
|
|
@ -141,11 +141,6 @@ pub const SetExpr = struct {
|
||||||
value: *Expr,
|
value: *Expr,
|
||||||
};
|
};
|
||||||
|
|
||||||
pub const VariableExpr = struct {
|
|
||||||
tok: Token,
|
|
||||||
metadata: ?*comp.VariableMetadata = null,
|
|
||||||
};
|
|
||||||
|
|
||||||
pub const Expr = union(ExprType) {
|
pub const Expr = union(ExprType) {
|
||||||
Assign: AssignExpr,
|
Assign: AssignExpr,
|
||||||
|
|
||||||
|
@ -155,7 +150,6 @@ pub const Expr = union(ExprType) {
|
||||||
Struct: StructExpr,
|
Struct: StructExpr,
|
||||||
|
|
||||||
Variable: Token,
|
Variable: Token,
|
||||||
|
|
||||||
Grouping: *Expr,
|
Grouping: *Expr,
|
||||||
Call: CallExpr,
|
Call: CallExpr,
|
||||||
|
|
||||||
|
|
|
@ -1,10 +1,7 @@
|
||||||
const std = @import("std");
|
const std = @import("std");
|
||||||
const ast = @import("ast.zig");
|
const ast = @import("ast.zig");
|
||||||
|
|
||||||
pub const CompilationError = error{
|
pub const CompilationError = error{TypeError};
|
||||||
TypeError,
|
|
||||||
UnknownName,
|
|
||||||
};
|
|
||||||
|
|
||||||
pub const SymbolTable = std.hash_map.StringHashMap(SymbolData);
|
pub const SymbolTable = std.hash_map.StringHashMap(SymbolData);
|
||||||
pub const TypeList = std.ArrayList(SymbolUnderlyingType);
|
pub const TypeList = std.ArrayList(SymbolUnderlyingType);
|
||||||
|
@ -79,8 +76,6 @@ pub const FunctionSymbol = struct {
|
||||||
/// Parameters for a function are also a table instead of an ArrayList
|
/// Parameters for a function are also a table instead of an ArrayList
|
||||||
/// because we want to resolve identifiers to them.
|
/// because we want to resolve identifiers to them.
|
||||||
parameters: UnderlyingTypeMap,
|
parameters: UnderlyingTypeMap,
|
||||||
parameter_list: TypeList,
|
|
||||||
|
|
||||||
scope: *Scope,
|
scope: *Scope,
|
||||||
|
|
||||||
/// Find a given identifier in the function. Can resolve to either a parameter
|
/// Find a given identifier in the function. Can resolve to either a parameter
|
||||||
|
@ -128,31 +123,6 @@ const builtin_type_identifiers = [_][]const u8{ "i32", "i64", "bool" };
|
||||||
|
|
||||||
const builtin_types = [_]SymbolUnderlyingTypeEnum{ .Integer32, .Integer64, .Bool };
|
const builtin_types = [_]SymbolUnderlyingTypeEnum{ .Integer32, .Integer64, .Bool };
|
||||||
|
|
||||||
const Using = enum {
|
|
||||||
Scope,
|
|
||||||
Function,
|
|
||||||
};
|
|
||||||
|
|
||||||
pub const VariableMetadata = struct {
|
|
||||||
typ: SymbolUnderlyingType,
|
|
||||||
|
|
||||||
using: Using,
|
|
||||||
|
|
||||||
from_scope: ?*Scope = null,
|
|
||||||
from_function: ?*FunctionSymbol = null,
|
|
||||||
|
|
||||||
pub fn withScope(scope: *Scope, typ: SymbolUnderlyingType) VariableMetadata {
|
|
||||||
return VariableMetadata{ .typ = typ, .from_scope = scope, .using = .Scope };
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn withParam(func: *FunctionSymbol, typ: SymbolUnderlyingType) VariableMetadata {
|
|
||||||
return VariableMetadata{ .typ = typ, .from_function = func, .using = .Function };
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
// TODO rm const?
|
|
||||||
pub const VariableMetadataMap = std.AutoHashMap(*const ast.Expr, VariableMetadata);
|
|
||||||
|
|
||||||
/// Represents the context for a full compiler run.
|
/// Represents the context for a full compiler run.
|
||||||
/// This is used to manage the symbol table for the compilation unit, etc.
|
/// This is used to manage the symbol table for the compilation unit, etc.
|
||||||
pub const CompilationContext = struct {
|
pub const CompilationContext = struct {
|
||||||
|
@ -162,21 +132,13 @@ pub const CompilationContext = struct {
|
||||||
cur_function: ?*FunctionSymbol = null,
|
cur_function: ?*FunctionSymbol = null,
|
||||||
current_scope: ?*Scope = null,
|
current_scope: ?*Scope = null,
|
||||||
|
|
||||||
metadata_map: VariableMetadataMap,
|
|
||||||
|
|
||||||
pub fn init(allocator: *std.mem.Allocator) CompilationContext {
|
pub fn init(allocator: *std.mem.Allocator) CompilationContext {
|
||||||
return CompilationContext{
|
return CompilationContext{
|
||||||
.allocator = allocator,
|
.allocator = allocator,
|
||||||
.symbol_table = SymbolTable.init(allocator),
|
.symbol_table = SymbolTable.init(allocator),
|
||||||
.metadata_map = VariableMetadataMap.init(allocator),
|
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn deinit(self: *@This()) void {
|
|
||||||
self.symbol_table.deinit();
|
|
||||||
self.metadata_map.deinit();
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Create a new scope out of the current one and set it as the current.
|
/// Create a new scope out of the current one and set it as the current.
|
||||||
pub fn bumpScope(self: *@This(), scope_id: ?[]const u8) !void {
|
pub fn bumpScope(self: *@This(), scope_id: ?[]const u8) !void {
|
||||||
if (self.current_scope == null) {
|
if (self.current_scope == null) {
|
||||||
|
@ -277,7 +239,6 @@ pub const CompilationContext = struct {
|
||||||
.decl = decl,
|
.decl = decl,
|
||||||
.return_type = ret_type,
|
.return_type = ret_type,
|
||||||
.parameters = type_map,
|
.parameters = type_map,
|
||||||
.parameter_list = param_types,
|
|
||||||
.scope = scope,
|
.scope = scope,
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
|
@ -325,43 +286,4 @@ pub const CompilationContext = struct {
|
||||||
|
|
||||||
return sym_kv.?.value;
|
return sym_kv.?.value;
|
||||||
}
|
}
|
||||||
|
|
||||||
fn resolveVarTypeInScope(
|
|
||||||
self: *@This(),
|
|
||||||
scope_opt: ?*Scope,
|
|
||||||
name: []const u8,
|
|
||||||
) ?VariableMetadata {
|
|
||||||
if (scope_opt == null) return null;
|
|
||||||
var scope = scope_opt.?;
|
|
||||||
|
|
||||||
var kv_opt = scope.env.get(name);
|
|
||||||
if (kv_opt) |kv| {
|
|
||||||
return VariableMetadata.withScope(scope, kv.value);
|
|
||||||
} else {
|
|
||||||
return self.resolveVarTypeInScope(scope.parent, name);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Resolve a given name's type, assuming it is a variable.
|
|
||||||
pub fn resolveVarType(self: *@This(), name: []const u8) !VariableMetadata {
|
|
||||||
var var_type: ?VariableMetadata = null;
|
|
||||||
|
|
||||||
if (self.current_scope) |scope| {
|
|
||||||
var_type = self.resolveVarTypeInScope(scope, name);
|
|
||||||
if (var_type) |typ| return typ;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (self.cur_function) |cur_function| {
|
|
||||||
var kv_opt = cur_function.parameters.get(name);
|
|
||||||
if (kv_opt) |kv| return VariableMetadata.withParam(cur_function, kv.value);
|
|
||||||
}
|
|
||||||
|
|
||||||
std.debug.warn("Unknown name {}\n", name);
|
|
||||||
return CompilationError.UnknownName;
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn insertMetadata(self: *@This(), ptr: *const ast.Expr, metadata: VariableMetadata) !void {
|
|
||||||
std.debug.assert(ast.ExprType(ptr.*) == .Variable);
|
|
||||||
_ = try self.metadata_map.put(ptr, metadata);
|
|
||||||
}
|
|
||||||
};
|
};
|
||||||
|
|
|
@ -412,9 +412,9 @@ pub const Parser = struct {
|
||||||
return expr;
|
return expr;
|
||||||
}
|
}
|
||||||
|
|
||||||
fn mkVariable(self: *Parser, tok: Token) !*ast.Expr {
|
fn mkVariable(self: *Parser, variable: Token) !*ast.Expr {
|
||||||
var expr = try self.allocator.create(Expr);
|
var expr = try self.allocator.create(Expr);
|
||||||
expr.* = Expr{ .Variable = tok };
|
expr.* = Expr{ .Variable = variable };
|
||||||
|
|
||||||
return expr;
|
return expr;
|
||||||
}
|
}
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue