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_or_zero :: inline (ptr: *$T, custom_init: (*T) = null) {
|
||||||
init :: initializer_of(T);
|
|
||||||
if custom_init != null {
|
if custom_init != null {
|
||||||
custom_init(ptr);
|
custom_init(ptr);
|
||||||
}
|
}
|
||||||
|
|
||||||
#if init != null {
|
init :: initializer_of(T);
|
||||||
|
if init != null {
|
||||||
inline init(ptr);
|
inline init(ptr);
|
||||||
}
|
}
|
||||||
else {
|
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