strings handled as built-in struct, and added immutable keyword

This commit is contained in:
uan
2026-02-07 11:06:55 +01:00
parent c0bbb82e71
commit 99d63ff769
4 changed files with 62 additions and 28 deletions

View File

@@ -24,6 +24,7 @@ fn mangle_struct(name string) string {
fn get_type_format(type string) string { fn get_type_format(type string) string {
dump(type)
return match type { return match type {
'int', 'bool' {'d'} 'int', 'bool' {'d'}
'real' {'f'} 'real' {'f'}
@@ -46,7 +47,7 @@ fn (mut g Generator) get_c_type(typ string) string {
return match typ { return match typ {
'real' {'float'} 'real' {'float'}
'int' {'int32_t'} 'int' {'int32_t'}
'string' {'char*'} 'string' {'OneString'}
else {typ} else {typ}
} }
} }
@@ -70,12 +71,16 @@ fn (mut g Generator) gen_class_print_func(stmt ClassDecl) {
g.out.writeln('for(int i=0; i<indent + 1; i++) printf(" ");') g.out.writeln('for(int i=0; i<indent + 1; i++) printf(" ");')
g.out.write_string('printf("${member.name}: ");') g.out.write_string('printf("${member.name}: ");')
if g.symbols.lookup_class(member.type) != none { if member.type != 'string' && g.symbols.lookup_class(member.type) != none {
inner_struct_name := mangle_struct(member.type) inner_struct_name := mangle_struct(member.type)
g.out.writeln('print_${inner_struct_name}(s.${member.name}, indent + 1);') g.out.writeln('print_${inner_struct_name}(s.${member.name}, indent + 1);')
} else { } else {
format := get_type_format(member.type) format := get_type_format(member.type)
g.out.writeln('printf("%${format}\\n", s.${member.name});') g.out.write_string('printf("%${format}\\n", s.${member.name}')
if member.type == 'string' {
g.out.write_string('.string')
}
g.out.writeln(');')
} }
} }
@@ -168,7 +173,7 @@ fn (mut g Generator) gen_expr(expr Expr) {
g.out.write_string(expr.val.str()) g.out.write_string(expr.val.str())
} }
StringLiteral { StringLiteral {
g.out.write_string('\"${expr.val}\"') g.out.write_string('(OneString){\"${expr.val}\", ${expr.val.len}}')
} }
Variable { Variable {
g.out.write_string(mangle_var(expr.name)) g.out.write_string(mangle_var(expr.name))
@@ -188,16 +193,20 @@ fn (mut g Generator) gen_expr(expr Expr) {
for i < expr.exprs.len { for i < expr.exprs.len {
inner_expr := expr.exprs[i]; inner_expr := expr.exprs[i];
expr_type := expr.types[i]; expr_type := expr.types[i];
if g.symbols.lookup_class(expr_type) != none { if expr_type != 'string' && g.symbols.lookup_class(expr_type) != none {
class_name := mangle_struct(expr_type) class_name := mangle_struct(expr_type)
g.out.write_string('print_${class_name}(') g.out.write_string('print_${class_name}(')
g.gen_expr(inner_expr) g.gen_expr(inner_expr)
g.out.write_string(', 0);') g.out.write_string(', 0);')
} else {
g.out.write_string('printf(\"') g.out.write_string('printf(\"')
format := get_type_format(expr_type) format := get_type_format(expr_type)
g.out.write_string('%${format}') g.out.write_string('%${format}')
g.out.write_string('\", ') g.out.write_string('\", ')
g.gen_expr(inner_expr) g.gen_expr(inner_expr)
if expr_type == 'string' {
g.out.write_string('.string')
}
g.out.write_string(');') g.out.write_string(');')
} }
i++; i++;
@@ -254,7 +263,7 @@ fn (mut g Generator) gen_c(program []Stmt) string {
g.out.writeln('#include <stdio.h>') g.out.writeln('#include <stdio.h>')
g.out.writeln('#include <stdbool.h>') g.out.writeln('#include <stdbool.h>')
g.out.writeln('#include <stdint.h>') g.out.writeln('#include <stdint.h>')
//g.out.writeln('typedef struct __one_string_builtin__ {\nchar* string;\nint len;\n} string;') g.out.writeln('typedef struct {\nchar* string;\nint len;\n} OneString;')
for stmt in program { for stmt in program {
g.gen_stmt(stmt) g.gen_stmt(stmt)
} }

View File

@@ -5,6 +5,7 @@ import term
enum TokenType as u8 { enum TokenType as u8 {
kw_let kw_let
kw_const kw_const
kw_immutable
type type
kw_if kw_if
kw_else kw_else
@@ -108,6 +109,7 @@ fn toktype_from_kw(kw string) TokenType {
'true', 'false' {.boolean} 'true', 'false' {.boolean}
'print' {.kw_print} 'print' {.kw_print}
'class' {.kw_class} 'class' {.kw_class}
'immutable' {.kw_immutable}
else {.unknown} else {.unknown}
} }
} }
@@ -127,7 +129,7 @@ fn is_real(str string) bool {
fn is_keyword(str string) bool { fn is_keyword(str string) bool {
return [ return [
"void", "int", "real", "bool", "string", "if", "else", "elif", "for", "break", "fn", "return", "let", "const", "true", "false", "print", "class" "void", "int", "real", "bool", "string", "if", "else", "elif", "for", "break", "fn", "return", "let", "const", "true", "false", "print", "class", "immutable"
].contains(str) ].contains(str)
} }

BIN
one

Binary file not shown.

View File

@@ -32,6 +32,7 @@ type SymbolInfo = VarSymbolInfo | FuncSymbolInfo | ClassSymbolInfo
struct VarSymbolInfo { struct VarSymbolInfo {
type string type string
is_immutable bool
} }
struct FuncSymbolInfo { struct FuncSymbolInfo {
@@ -96,7 +97,10 @@ fn (mut s SymbolTable) lookup_func(name string) ?FuncSymbolInfo {
fn (mut s SymbolTable) define_class(name string, members []ClassMember) { fn (mut s SymbolTable) define_class(name string, members []ClassMember) {
mut members_info := map[string]VarSymbolInfo{} mut members_info := map[string]VarSymbolInfo{}
for member in members { for member in members {
members_info[member.name] = VarSymbolInfo{member.type} members_info[member.name] = VarSymbolInfo{
type: member.type,
is_immutable: member.is_immutable
}
} }
s.structs[name] = ClassSymbolInfo{name: name, members_info: members_info} s.structs[name] = ClassSymbolInfo{name: name, members_info: members_info}
} }
@@ -157,11 +161,13 @@ struct TypeExpr {
struct ClassMember { struct ClassMember {
name string name string
type string type string
is_immutable bool
} }
struct MemberAccess { struct MemberAccess {
from Expr from Expr
member string member string
member_type string
} }
struct ClassInstantiation { struct ClassInstantiation {
@@ -349,10 +355,6 @@ fn (mut p Parser) parse_ident(ident string) Expr {
} }
} }
if p.inside_struct {
return p.parse_class_member(ident)
}
return match p.peek().type { return match p.peek().type {
.increment, .decrement {UnaryExpr {ident: ident, op: p.next().text}} .increment, .decrement {UnaryExpr {ident: ident, op: p.next().text}}
.lparen {p.parse_call(ident)} .lparen {p.parse_call(ident)}
@@ -363,25 +365,34 @@ fn (mut p Parser) parse_ident(ident string) Expr {
fn (mut p Parser) parse_member_access(from Expr) MemberAccess { fn (mut p Parser) parse_member_access(from Expr) MemberAccess {
member_tok := p.next() member_tok := p.next()
if member_tok.type != .identifier {parse_error("Expected identifier after member access")} if member_tok.type != .identifier {parse_error("Expected identifier after member access")}
return MemberAccess {from: from, member: member_tok.text} from_class := p.symbols.lookup_class(p.get_expr_type(from)) or {panic("Accessing member from non-class type")}
if !(member_tok.text in from_class.members_info) {panic("Accessing undefined member ${member_tok.text}")}
member_type := from_class.members_info[member_tok.text].type
return MemberAccess {from: from, member: member_tok.text, member_type: member_type}
} }
fn (mut p Parser) parse_class_member(name string) ClassMember { fn (mut p Parser) parse_class_member() ClassMember {
mut is_immut := false
if p.peek().type == .kw_immutable {
is_immut = true
p.next()
}
member_name := p.peek().text
p.expect(.identifier) p.expect(.identifier)
type_tok := p.peek() type_tok := p.peek()
type_name := match type_tok.type { type_name := match type_tok.type {
.type {type_tok.text} .type {type_tok.text}
.identifier { .identifier {
p.expect_ident_is_class(type_tok.text) p.expect_ident_is_class(type_tok.text)
type_tok.text type_tok.text
} }
else{parse_error("Expected type after class member ${name} in declaration, got ${p.peek().type}")} else{parse_error("Expected type after class member ${member_name} in declaration, got ${p.peek().type}")}
} }
p.next() p.next()
p.expect(.semicolon) p.expect(.semicolon)
return ClassMember{name: name, type: type_name} return ClassMember{name: member_name, type: type_name is_immutable: is_immut}
} }
fn (mut p Parser) parse_class_inst(name string) ClassInstantiation { fn (mut p Parser) parse_class_inst(name string) ClassInstantiation {
@@ -439,6 +450,20 @@ fn (mut p Parser) parse_print() PrintExpr {
} }
fn (mut p Parser) parse_binary(left Expr, op string, prec Precedence) BinaryExpr { fn (mut p Parser) parse_binary(left Expr, op string, prec Precedence) BinaryExpr {
if op in ['=', '+=', '-=', '*=', '/='] {
if left is MemberAccess {
from_type := p.get_expr_type(left.from)
if class_info := p.symbols.lookup_class(from_type) {
if member_info := class_info.members_info[left.member] {
if member_info.is_immutable {
parse_error("Cannot assign to immutable member ${left.member} in class ${from_type}")
}
}
}
}
}
right := p.parse_expr(prec) right := p.parse_expr(prec)
binary_expr := BinaryExpr{left, op, right} binary_expr := BinaryExpr{left, op, right}
@@ -513,13 +538,7 @@ fn (mut p Parser) get_expr_type(expr Expr) string {
fninfo.type fninfo.type
} }
MemberAccess { MemberAccess {
mut type_from := p.get_expr_type(expr.from) expr.member_type
classinfo := p.symbols.lookup_class(type_from)or{parse_error("Non-existant class ${type_from}")}
if expr.member in classinfo.members_info {
classinfo.members_info[expr.member].type
} else {
parse_error("Undefined class member ${expr.member}")
}
} }
ClassInstantiation {expr.name} ClassInstantiation {expr.name}
else {"Tried getting type of unexpected Expr"} else {"Tried getting type of unexpected Expr"}
@@ -695,8 +714,8 @@ fn (mut p Parser) parse_class() ClassDecl {
p.expect(.identifier) p.expect(.identifier)
p.expect(.lbracket) p.expect(.lbracket)
mut members := []ClassMember{} mut members := []ClassMember{}
for p.peek().type == .identifier { for p.peek().type != .rbracket {
members << p.parse_class_member(p.peek().text) members << p.parse_class_member()
} }
p.expect(.rbracket) p.expect(.rbracket)
p.symbols.define_class(name, members) p.symbols.define_class(name, members)
@@ -793,6 +812,10 @@ fn (mut p Parser) parse_block(no_scope bool) Block {
} }
fn (mut p Parser) parse_program() ([]Stmt, SymbolTable) { fn (mut p Parser) parse_program() ([]Stmt, SymbolTable) {
p.symbols.define_class('string',[
ClassMember{'len', 'int', true}
])
p.symbols.variable_scopes << map[string]VarSymbolInfo{} p.symbols.variable_scopes << map[string]VarSymbolInfo{}
for p.peek().type != .eof { for p.peek().type != .eof {
p.statements << p.parse_statement() p.statements << p.parse_statement()