fix memory, add vm
This commit is contained in:
parent
3f3d96cc30
commit
ee25688b42
3 changed files with 306 additions and 2 deletions
|
|
@ -63,12 +63,12 @@ align_to :: (ptr: int, align: int = Default_Align) -> int {
|
|||
}
|
||||
|
||||
init_or_zero :: inline (ptr: *$T, custom_init: (*T) = null) {
|
||||
init :: initializer_of(T);
|
||||
if custom_init != null {
|
||||
custom_init(ptr);
|
||||
}
|
||||
|
||||
#if init != null {
|
||||
init :: initializer_of(T);
|
||||
if init != null {
|
||||
inline init(ptr);
|
||||
}
|
||||
else {
|
||||
|
|
|
|||
7
vm/module.jai
Normal file
7
vm/module.jai
Normal file
|
|
@ -0,0 +1,7 @@
|
|||
#module_parameters(RUN_TESTS := false);
|
||||
|
||||
#scope_file;
|
||||
|
||||
#if RUN_TESTS {
|
||||
test :: #import "jc/test";
|
||||
}
|
||||
297
vm/parser.jai
Normal file
297
vm/parser.jai
Normal file
|
|
@ -0,0 +1,297 @@
|
|||
Token :: struct {
|
||||
kind: Kind;
|
||||
str: string;
|
||||
|
||||
Kind :: enum {
|
||||
invalid;
|
||||
end_of_file;
|
||||
|
||||
symbol;
|
||||
number;
|
||||
string;
|
||||
|
||||
kw_var;
|
||||
kw_def;
|
||||
kw_type;
|
||||
kw_do;
|
||||
kw_end;
|
||||
|
||||
equal :: #char "=";
|
||||
plus :: #char "+";
|
||||
minus :: #char "-";
|
||||
star :: #char "*";
|
||||
f_slash :: #char "/";
|
||||
b_slash :: #char "\\";
|
||||
|
||||
l_paren :: #char "(";
|
||||
r_paren :: #char ")";
|
||||
l_square :: #char "[";
|
||||
r_square :: #char "]";
|
||||
l_brace :: #char "{";
|
||||
r_brace :: #char "}";
|
||||
comma :: #char ",";
|
||||
dot :: #char ".";
|
||||
colon :: #char ":";
|
||||
semicolon :: #char ";";
|
||||
}
|
||||
}
|
||||
|
||||
Node :: struct {
|
||||
kind: Kind;
|
||||
|
||||
Kind :: enum {
|
||||
invalid;
|
||||
|
||||
decl_start;
|
||||
var;
|
||||
decl_end;
|
||||
|
||||
expr_start;
|
||||
symbol;
|
||||
literal;
|
||||
expr_end;
|
||||
}
|
||||
}
|
||||
|
||||
Node_Var :: struct {
|
||||
#as using n: Node;
|
||||
n.kind = .var;
|
||||
|
||||
symbol: *Node;
|
||||
type_expr: *Node;
|
||||
value_expr: *Node;
|
||||
}
|
||||
|
||||
Node_Symbol :: struct {
|
||||
#as using n: Node;
|
||||
n.kind = .symbol;
|
||||
|
||||
str: string;
|
||||
}
|
||||
|
||||
Node_Literal :: struct {
|
||||
#as using n: Node;
|
||||
n.kind = .literal;
|
||||
|
||||
union {
|
||||
}
|
||||
}
|
||||
|
||||
Parser :: struct {
|
||||
allocator: Allocator;
|
||||
toplevel: [..]*Node;
|
||||
|
||||
previous: Token;
|
||||
filename: string;
|
||||
source: string;
|
||||
offset: int;
|
||||
}
|
||||
|
||||
init :: (p: *Parser, allocator: Allocator) {
|
||||
p.allocator = allocator;
|
||||
p.toplevel.allocator = allocator;
|
||||
}
|
||||
|
||||
parse_string :: (p: *Parser, source: string) -> bool {
|
||||
p.source = source;
|
||||
p.offset = 0;
|
||||
|
||||
while !at_end(p) {
|
||||
t := peek_token(p);
|
||||
if t.kind == .invalid || t.kind == .end_of_file {
|
||||
break;
|
||||
}
|
||||
|
||||
node := parse_toplevel_declaration(p);
|
||||
if node == null break;
|
||||
|
||||
array.append(*p.toplevel, node);
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
#scope_file;
|
||||
|
||||
parse_toplevel_declaration :: (p: *Parser) -> *Node {
|
||||
t, ok := expect_token(p, .kw_var);
|
||||
if ok == false return null;
|
||||
|
||||
s:, ok = expect_token(p, .symbol);
|
||||
if ok == false return null;
|
||||
|
||||
type_expr: *Node;
|
||||
value_expr: *Node;
|
||||
|
||||
// var sym int
|
||||
// var sym int = value
|
||||
// var sym = value
|
||||
|
||||
t = peek_token(p);
|
||||
if t.kind == .equal {
|
||||
consume_token(p);
|
||||
value_expr = parse_expression(p);
|
||||
}
|
||||
else {
|
||||
type_expr = parse_type_expression(p);
|
||||
if type_expr == null return null;
|
||||
|
||||
if peek_token(p).kind == .equal {
|
||||
consume_token(p);
|
||||
value_expr = parse_expression(p);
|
||||
}
|
||||
}
|
||||
|
||||
symbol := make_node(p, Node_Symbol);
|
||||
symbol.str = s.str;
|
||||
|
||||
node := make_node(p, Node_Var);
|
||||
node.symbol = symbol;
|
||||
node.type_expr = type_expr;
|
||||
node.value_expr = value_expr;
|
||||
|
||||
return node;
|
||||
}
|
||||
|
||||
parse_type_expression :: (p: *Parser) -> *Node {
|
||||
t, ok := expect_token(p, .symbol, .star);
|
||||
if ok == false return null;
|
||||
|
||||
if t.kind == {
|
||||
case .symbol;
|
||||
node := make_node(p, Node_Symbol);
|
||||
node.str = t.str;
|
||||
return node;
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
parse_expression :: (p: *Parser) -> *Node {
|
||||
return null;
|
||||
}
|
||||
|
||||
make_node :: (p: *Parser, $T: Type) -> *T {
|
||||
return mem.request_memory(T,, allocator = p.allocator);
|
||||
}
|
||||
|
||||
peek_token :: (p: *Parser) -> Token {
|
||||
copy := p.*;
|
||||
return consume_token(*copy);
|
||||
}
|
||||
|
||||
at_end :: (p: *Parser) -> bool {
|
||||
return p.offset >= p.source.count;
|
||||
}
|
||||
|
||||
starts_symbol :: (c: u8) -> bool {
|
||||
return (c >= "a" && c <= "z") ||
|
||||
(c >= "A" && c <= "Z") ||
|
||||
(c == "_");
|
||||
}
|
||||
continues_symbol :: (c: u8) -> bool {
|
||||
return starts_symbol(c) || (c >= "0" && c <= "9");
|
||||
}
|
||||
|
||||
starts_number :: (c: u8) -> bool {
|
||||
return (c >= "0" && c <= "9");
|
||||
}
|
||||
continues_number :: (c: u8) -> bool {
|
||||
return starts_number(c) || c == ".";
|
||||
}
|
||||
|
||||
consume_token :: (p: *Parser) -> Token {
|
||||
if at_end(p) return .{ kind = .end_of_file };
|
||||
|
||||
c := p.source[p.offset];
|
||||
while !at_end(p) {
|
||||
c = p.source[p.offset];
|
||||
if c == {
|
||||
case " "; #through;
|
||||
case "\n"; #through;
|
||||
case "\t";
|
||||
p.offset += 1;
|
||||
case;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if starts_symbol(c) {
|
||||
t := Token.{ str = .{ data = p.source.data + p.offset } };
|
||||
while !at_end(p) {
|
||||
c = p.source[p.offset];
|
||||
if !continues_symbol(c) break;
|
||||
p.offset += 1;
|
||||
}
|
||||
|
||||
t.str.count = (p.source.data + p.offset) - t.str.data;
|
||||
if t.str == {
|
||||
case "var"; t.kind = .kw_var;
|
||||
case "def"; t.kind = .kw_def;
|
||||
case "do"; t.kind = .kw_do;
|
||||
case "end"; t.kind = .kw_end;
|
||||
case "type"; t.kind = .kw_type;
|
||||
case; t.kind = .symbol;
|
||||
}
|
||||
|
||||
return t;
|
||||
}
|
||||
|
||||
if starts_number(c) {
|
||||
t := Token.{ kind = .number, str = .{ data = p.source.data + p.offset } };
|
||||
while !at_end(p) {
|
||||
c = p.source[p.offset];
|
||||
if !continues_number(c) break;
|
||||
p.offset += 1;
|
||||
}
|
||||
|
||||
t.str.count = (p.source.data + p.offset) - t.str.data;
|
||||
return t;
|
||||
}
|
||||
|
||||
if c == {
|
||||
case "+"; #through;
|
||||
case "-"; #through;
|
||||
case "*"; #through;
|
||||
case "/"; #through;
|
||||
case "="; #through;
|
||||
case "("; #through;
|
||||
case ")"; #through;
|
||||
case "["; #through;
|
||||
case "]"; #through;
|
||||
case "{"; #through;
|
||||
case "}";
|
||||
s := string.{ data = p.source.data + p.offset, count = 1 };
|
||||
p.offset += 1;
|
||||
return .{ kind = xx c, str = s };
|
||||
}
|
||||
|
||||
s := string.{ data = p.source.data + p.offset, count = 1 };
|
||||
return .{ kind = .invalid, str = s };
|
||||
}
|
||||
|
||||
expect_token :: (p: *Parser, kinds: ..Token.Kind) -> Token, bool {
|
||||
t := consume_token(p);
|
||||
for kinds if it == t.kind {
|
||||
return t, true;
|
||||
}
|
||||
|
||||
return t, false;
|
||||
}
|
||||
|
||||
#run {
|
||||
parser: Parser;
|
||||
init(*parser, context.allocator);
|
||||
|
||||
ok := parse_string(*parser, #string END
|
||||
var x = 10
|
||||
var y = 20
|
||||
END);
|
||||
}
|
||||
|
||||
mem :: #import "jc/memory";
|
||||
array :: #import "jc/array";
|
||||
|
||||
basic :: #import "Basic"; // @future
|
||||
strings :: #import "String"; // @future
|
||||
Loading…
Reference in a new issue