freelang-v4 4.3.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +548 -0
- package/dist/ast.d.ts +367 -0
- package/dist/ast.js +4 -0
- package/dist/ast.js.map +1 -0
- package/dist/async-basic.test.d.ts +1 -0
- package/dist/async-basic.test.js +88 -0
- package/dist/async-basic.test.js.map +1 -0
- package/dist/async-jest.test.d.ts +1 -0
- package/dist/async-jest.test.js +99 -0
- package/dist/async-jest.test.js.map +1 -0
- package/dist/channel-jest.test.d.ts +1 -0
- package/dist/channel-jest.test.js +148 -0
- package/dist/channel-jest.test.js.map +1 -0
- package/dist/checker-jest.test.d.ts +1 -0
- package/dist/checker-jest.test.js +160 -0
- package/dist/checker-jest.test.js.map +1 -0
- package/dist/checker.d.ts +149 -0
- package/dist/checker.js +1565 -0
- package/dist/checker.js.map +1 -0
- package/dist/checker.test.d.ts +1 -0
- package/dist/checker.test.js +217 -0
- package/dist/checker.test.js.map +1 -0
- package/dist/compiler-jest.test.d.ts +1 -0
- package/dist/compiler-jest.test.js +233 -0
- package/dist/compiler-jest.test.js.map +1 -0
- package/dist/compiler.d.ts +127 -0
- package/dist/compiler.js +1588 -0
- package/dist/compiler.js.map +1 -0
- package/dist/compiler.test.d.ts +1 -0
- package/dist/compiler.test.js +313 -0
- package/dist/compiler.test.js.map +1 -0
- package/dist/db-100m-full.d.ts +5 -0
- package/dist/db-100m-full.js +78 -0
- package/dist/db-100m-full.js.map +1 -0
- package/dist/db-100m-no-index.d.ts +12 -0
- package/dist/db-100m-no-index.js +119 -0
- package/dist/db-100m-no-index.js.map +1 -0
- package/dist/db-100m-real.d.ts +5 -0
- package/dist/db-100m-real.js +131 -0
- package/dist/db-100m-real.js.map +1 -0
- package/dist/db-100m-streaming.d.ts +15 -0
- package/dist/db-100m-streaming.js +164 -0
- package/dist/db-100m-streaming.js.map +1 -0
- package/dist/db-100m-test.d.ts +5 -0
- package/dist/db-100m-test.js +111 -0
- package/dist/db-100m-test.js.map +1 -0
- package/dist/db-jest.test.d.ts +1 -0
- package/dist/db-jest.test.js +182 -0
- package/dist/db-jest.test.js.map +1 -0
- package/dist/db-runtime.d.ts +24 -0
- package/dist/db-runtime.js +204 -0
- package/dist/db-runtime.js.map +1 -0
- package/dist/db.d.ts +249 -0
- package/dist/db.js +593 -0
- package/dist/db.js.map +1 -0
- package/dist/file-io-jest.test.d.ts +1 -0
- package/dist/file-io-jest.test.js +225 -0
- package/dist/file-io-jest.test.js.map +1 -0
- package/dist/for-of-jest.test.d.ts +1 -0
- package/dist/for-of-jest.test.js +230 -0
- package/dist/for-of-jest.test.js.map +1 -0
- package/dist/for-of.test.d.ts +1 -0
- package/dist/for-of.test.js +305 -0
- package/dist/for-of.test.js.map +1 -0
- package/dist/function-literal-jest.test.d.ts +1 -0
- package/dist/function-literal-jest.test.js +180 -0
- package/dist/function-literal-jest.test.js.map +1 -0
- package/dist/function-literal.test.d.ts +1 -0
- package/dist/function-literal.test.js +245 -0
- package/dist/function-literal.test.js.map +1 -0
- package/dist/generics-jest.test.d.ts +1 -0
- package/dist/generics-jest.test.js +93 -0
- package/dist/generics-jest.test.js.map +1 -0
- package/dist/ir-gen.d.ts +15 -0
- package/dist/ir-gen.js +400 -0
- package/dist/ir-gen.js.map +1 -0
- package/dist/ir.d.ts +114 -0
- package/dist/ir.js +5 -0
- package/dist/ir.js.map +1 -0
- package/dist/lexer.d.ts +110 -0
- package/dist/lexer.js +467 -0
- package/dist/lexer.js.map +1 -0
- package/dist/lexer.test.d.ts +1 -0
- package/dist/lexer.test.js +426 -0
- package/dist/lexer.test.js.map +1 -0
- package/dist/main.d.ts +2 -0
- package/dist/main.js +241 -0
- package/dist/main.js.map +1 -0
- package/dist/module-jest.test.d.ts +1 -0
- package/dist/module-jest.test.js +123 -0
- package/dist/module-jest.test.js.map +1 -0
- package/dist/parser.d.ts +56 -0
- package/dist/parser.js +1060 -0
- package/dist/parser.js.map +1 -0
- package/dist/parser.test.d.ts +1 -0
- package/dist/parser.test.js +461 -0
- package/dist/parser.test.js.map +1 -0
- package/dist/pattern-matching-jest.test.d.ts +1 -0
- package/dist/pattern-matching-jest.test.js +158 -0
- package/dist/pattern-matching-jest.test.js.map +1 -0
- package/dist/pkg/init.d.ts +1 -0
- package/dist/pkg/init.js +118 -0
- package/dist/pkg/init.js.map +1 -0
- package/dist/pkg/install.d.ts +1 -0
- package/dist/pkg/install.js +77 -0
- package/dist/pkg/install.js.map +1 -0
- package/dist/pkg/registry.d.ts +23 -0
- package/dist/pkg/registry.js +106 -0
- package/dist/pkg/registry.js.map +1 -0
- package/dist/pkg/run.d.ts +1 -0
- package/dist/pkg/run.js +76 -0
- package/dist/pkg/run.js.map +1 -0
- package/dist/pkg/toml.d.ts +5 -0
- package/dist/pkg/toml.js +117 -0
- package/dist/pkg/toml.js.map +1 -0
- package/dist/repl.d.ts +15 -0
- package/dist/repl.js +197 -0
- package/dist/repl.js.map +1 -0
- package/dist/runtime/bytecode.d.ts +92 -0
- package/dist/runtime/bytecode.js +253 -0
- package/dist/runtime/bytecode.js.map +1 -0
- package/dist/runtime/value.d.ts +102 -0
- package/dist/runtime/value.js +302 -0
- package/dist/runtime/value.js.map +1 -0
- package/dist/runtime/vm.d.ts +65 -0
- package/dist/runtime/vm.js +293 -0
- package/dist/runtime/vm.js.map +1 -0
- package/dist/struct-instance-jest.test.d.ts +1 -0
- package/dist/struct-instance-jest.test.js +209 -0
- package/dist/struct-instance-jest.test.js.map +1 -0
- package/dist/struct-instance.test.d.ts +1 -0
- package/dist/struct-instance.test.js +291 -0
- package/dist/struct-instance.test.js.map +1 -0
- package/dist/struct-jest.test.d.ts +1 -0
- package/dist/struct-jest.test.js +176 -0
- package/dist/struct-jest.test.js.map +1 -0
- package/dist/struct.test.d.ts +1 -0
- package/dist/struct.test.js +231 -0
- package/dist/struct.test.js.map +1 -0
- package/dist/trait-jest.test.d.ts +1 -0
- package/dist/trait-jest.test.js +120 -0
- package/dist/trait-jest.test.js.map +1 -0
- package/dist/vm-jest.test.d.ts +1 -0
- package/dist/vm-jest.test.js +569 -0
- package/dist/vm-jest.test.js.map +1 -0
- package/dist/vm.d.ts +81 -0
- package/dist/vm.js +1956 -0
- package/dist/vm.js.map +1 -0
- package/dist/vm.test.d.ts +1 -0
- package/dist/vm.test.js +337 -0
- package/dist/vm.test.js.map +1 -0
- package/dist/web-repl/sandbox.d.ts +11 -0
- package/dist/web-repl/sandbox.js +76 -0
- package/dist/web-repl/sandbox.js.map +1 -0
- package/dist/web-repl/server.d.ts +1 -0
- package/dist/web-repl/server.js +111 -0
- package/dist/web-repl/server.js.map +1 -0
- package/dist/while-loop-jest.test.d.ts +1 -0
- package/dist/while-loop-jest.test.js +201 -0
- package/dist/while-loop-jest.test.js.map +1 -0
- package/dist/while-loop.test.d.ts +1 -0
- package/dist/while-loop.test.js +262 -0
- package/dist/while-loop.test.js.map +1 -0
- package/docs/EXPERIENCE.md +787 -0
- package/docs/README.md +175 -0
- package/docs/V1_V2_V3_ANALYSIS.md +107 -0
- package/docs/_config.yml +36 -0
- package/docs/api-reference.md +459 -0
- package/docs/architecture.md +470 -0
- package/docs/benchmarks.md +295 -0
- package/docs/comparison.md +454 -0
- package/docs/index.md +335 -0
- package/docs/language-completeness.md +228 -0
- package/docs/learning-guide.md +651 -0
- package/package.json +65 -0
- package/src/api/deploy_key.fl +294 -0
- package/src/api/issue.fl +302 -0
- package/src/api/org.fl +356 -0
- package/src/api/repo.fl +394 -0
- package/src/api/team.fl +299 -0
- package/src/api/user.fl +385 -0
- package/src/api/webhook.fl +273 -0
- package/src/ast.ts +158 -0
- package/src/async-basic.test.ts +94 -0
- package/src/async-jest.test.ts +107 -0
- package/src/channel-jest.test.ts +158 -0
- package/src/checker-jest.test.ts +189 -0
- package/src/checker.test.ts +279 -0
- package/src/checker.ts +1861 -0
- package/src/commands/analyze.fl +227 -0
- package/src/commands/auth.fl +315 -0
- package/src/commands/batch.fl +349 -0
- package/src/commands/config.fl +199 -0
- package/src/commands/deploy_key.fl +352 -0
- package/src/commands/issue.fl +275 -0
- package/src/commands/main.fl +492 -0
- package/src/commands/org.fl +425 -0
- package/src/commands/repo.fl +581 -0
- package/src/commands/team.fl +244 -0
- package/src/commands/user.fl +423 -0
- package/src/commands/webhook.fl +400 -0
- package/src/compiler-jest.test.ts +275 -0
- package/src/compiler.test.ts +375 -0
- package/src/compiler.ts +1770 -0
- package/src/config.fl +175 -0
- package/src/core/batch.fl +355 -0
- package/src/core/cache.fl +284 -0
- package/src/core/ensure.fl +324 -0
- package/src/db-100m-full.ts +96 -0
- package/src/db-100m-no-index.ts +133 -0
- package/src/db-100m-real.ts +152 -0
- package/src/db-100m-streaming.ts +154 -0
- package/src/db-100m-test.ts +136 -0
- package/src/db-jest.test.ts +161 -0
- package/src/db-runtime.ts +242 -0
- package/src/db.ts +676 -0
- package/src/errors.fl +134 -0
- package/src/for-of-jest.test.ts +246 -0
- package/src/for-of.test.ts +308 -0
- package/src/function-literal-jest.test.ts +193 -0
- package/src/function-literal.test.ts +248 -0
- package/src/generics-jest.test.ts +104 -0
- package/src/http/client.fl +327 -0
- package/src/ir-gen.ts +459 -0
- package/src/ir.ts +80 -0
- package/src/lexer.test.ts +499 -0
- package/src/lexer.ts +522 -0
- package/src/main.ts +223 -0
- package/src/models.fl +162 -0
- package/src/module-jest.test.ts +145 -0
- package/src/parser.test.ts +542 -0
- package/src/parser.ts +1211 -0
- package/src/pattern-matching-jest.test.ts +170 -0
- package/src/pkg/init.ts +91 -0
- package/src/pkg/install.ts +56 -0
- package/src/pkg/registry.ts +103 -0
- package/src/pkg/run.ts +49 -0
- package/src/pkg/toml.ts +129 -0
- package/src/repl.ts +190 -0
- package/src/runtime/bytecode.ts +291 -0
- package/src/runtime/value.ts +322 -0
- package/src/runtime/vm.ts +354 -0
- package/src/self-host/bootstrap.fl +68 -0
- package/src/self-host/interpreter.fl +361 -0
- package/src/self-host/lexer-simple.fl +22 -0
- package/src/self-host/lexer.fl +305 -0
- package/src/self-host/parser.fl +580 -0
- package/src/struct-instance-jest.test.ts +221 -0
- package/src/struct-instance.test.ts +293 -0
- package/src/struct-jest.test.ts +187 -0
- package/src/struct.test.ts +234 -0
- package/src/trait-jest.test.ts +136 -0
- package/src/vm-jest.test.ts +754 -0
- package/src/vm.ts +1976 -0
- package/src/web-repl/public/index.html +50 -0
- package/src/web-repl/public/main.js +105 -0
- package/src/web-repl/public/style.css +225 -0
- package/src/web-repl/sandbox.ts +88 -0
- package/src/web-repl/server.ts +97 -0
- package/src/while-loop-jest.test.ts +218 -0
- package/src/while-loop.test.ts +267 -0
|
@@ -0,0 +1,68 @@
|
|
|
1
|
+
// ============================================================
|
|
2
|
+
// FreeLang v4 Self-Hosting Bootstrap (bootstrap.fl)
|
|
3
|
+
// Stage 2: Self-hosted Lexer → Parser → Interpreter
|
|
4
|
+
// Entry point for verifying lexer.fl independently
|
|
5
|
+
// ============================================================
|
|
6
|
+
|
|
7
|
+
// ============================================================
|
|
8
|
+
// Lexer Test
|
|
9
|
+
// ============================================================
|
|
10
|
+
|
|
11
|
+
fn test_lexer_simple() -> void {
|
|
12
|
+
println("=== Lexer Verification ===")
|
|
13
|
+
println("")
|
|
14
|
+
|
|
15
|
+
// Redirect: Execute lexer.fl directly via:
|
|
16
|
+
// node dist/main.js src/self-host/lexer.fl
|
|
17
|
+
println("Lexer loaded successfully.")
|
|
18
|
+
println("Run: node dist/main.js src/self-host/lexer.fl")
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
// ============================================================
|
|
22
|
+
// Parser Test
|
|
23
|
+
// ============================================================
|
|
24
|
+
|
|
25
|
+
fn test_parser_simple() -> void {
|
|
26
|
+
println("=== Parser Verification ===")
|
|
27
|
+
println("")
|
|
28
|
+
|
|
29
|
+
// Redirect: Execute parser.fl directly via:
|
|
30
|
+
// node dist/main.js src/self-host/parser.fl
|
|
31
|
+
println("Parser loaded successfully.")
|
|
32
|
+
println("Run: node dist/main.js src/self-host/parser.fl")
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
// ============================================================
|
|
36
|
+
// Interpreter Test
|
|
37
|
+
// ============================================================
|
|
38
|
+
|
|
39
|
+
fn test_interpreter_simple() -> void {
|
|
40
|
+
println("=== Interpreter Verification ===")
|
|
41
|
+
println("")
|
|
42
|
+
|
|
43
|
+
// Redirect: Execute interpreter.fl directly via:
|
|
44
|
+
// node dist/main.js src/self-host/interpreter.fl
|
|
45
|
+
println("Interpreter loaded successfully.")
|
|
46
|
+
println("Run: node dist/main.js src/self-host/interpreter.fl")
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
// ============================================================
|
|
50
|
+
// Bootstrap Entry Point
|
|
51
|
+
// ============================================================
|
|
52
|
+
|
|
53
|
+
fn main() -> void {
|
|
54
|
+
println("=== FreeLang v4 Self-Hosting Bootstrap ===")
|
|
55
|
+
println("")
|
|
56
|
+
println("Self-hosting components:")
|
|
57
|
+
println(" Stage 1: Lexer (lexer.fl)")
|
|
58
|
+
println(" Stage 2: Parser (parser.fl)")
|
|
59
|
+
println(" Stage 3: Interpreter (interpreter.fl)")
|
|
60
|
+
println("")
|
|
61
|
+
println("To test individual components:")
|
|
62
|
+
println(" > node dist/main.js src/self-host/lexer.fl")
|
|
63
|
+
println(" > node dist/main.js src/self-host/parser.fl")
|
|
64
|
+
println(" > node dist/main.js src/self-host/interpreter.fl")
|
|
65
|
+
println("")
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
main()
|
|
@@ -0,0 +1,361 @@
|
|
|
1
|
+
// ============================================================
|
|
2
|
+
// FreeLang v4 Self-Hosting Interpreter (interpreter.fl)
|
|
3
|
+
// Tree-walking interpreter - Execution phase
|
|
4
|
+
// ============================================================
|
|
5
|
+
|
|
6
|
+
// ============================================================
|
|
7
|
+
// Value Representation
|
|
8
|
+
// ============================================================
|
|
9
|
+
|
|
10
|
+
struct Value {
|
|
11
|
+
kind: str // "i32", "f64", "string", "bool", "array", "struct", "null", "fn", "error"
|
|
12
|
+
// Payload fields:
|
|
13
|
+
// - kind="i32": val_i32: i32
|
|
14
|
+
// - kind="f64": val_f64: f64
|
|
15
|
+
// - kind="string": val_string: str
|
|
16
|
+
// - kind="bool": val_bool: bool
|
|
17
|
+
// - kind="array": val_array: [Value]
|
|
18
|
+
// - kind="struct": val_type: str, val_fields: [Value]
|
|
19
|
+
// - kind="null": (no payload)
|
|
20
|
+
// - kind="fn": val_params: [str], val_body: [Stmt], val_env: Environment
|
|
21
|
+
// - kind="error": val_error: str
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
struct Environment {
|
|
25
|
+
vars: [str] // Variable names
|
|
26
|
+
values: [Value] // Corresponding values
|
|
27
|
+
parent: Environment // Parent scope (or null)
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
// ============================================================
|
|
31
|
+
// Runtime State
|
|
32
|
+
// ============================================================
|
|
33
|
+
|
|
34
|
+
struct Runtime {
|
|
35
|
+
globals: Environment
|
|
36
|
+
functions: [str]
|
|
37
|
+
function_bodies: [[Stmt]]
|
|
38
|
+
return_value: Value
|
|
39
|
+
break_flag: bool
|
|
40
|
+
continue_flag: bool
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
// ============================================================
|
|
44
|
+
// Environment Functions
|
|
45
|
+
// ============================================================
|
|
46
|
+
|
|
47
|
+
fn env_new() -> Environment {
|
|
48
|
+
return Environment { vars: [], values: [], parent: Environment { vars: [], values: [], parent: null } }
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
fn env_define(env: Environment, name: str, value: Value) -> Environment {
|
|
52
|
+
var vars = push(env.vars, name)
|
|
53
|
+
var values = push(env.values, value)
|
|
54
|
+
return Environment { vars: vars, values: values, parent: env.parent }
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
fn env_get(env: Environment, name: str) -> Value {
|
|
58
|
+
var i = 0
|
|
59
|
+
while i < length(env.vars) {
|
|
60
|
+
if env.vars[i] == name {
|
|
61
|
+
return env.values[i]
|
|
62
|
+
}
|
|
63
|
+
i = i + 1
|
|
64
|
+
}
|
|
65
|
+
// Check parent scope (if exists)
|
|
66
|
+
if env.parent != null {
|
|
67
|
+
return env_get(env.parent, name)
|
|
68
|
+
}
|
|
69
|
+
return Value { kind: "error", val_error: "Undefined variable: " + name }
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
fn env_set(env: Environment, name: str, value: Value) -> Environment {
|
|
73
|
+
var i = 0
|
|
74
|
+
while i < length(env.vars) {
|
|
75
|
+
if env.vars[i] == name {
|
|
76
|
+
var new_values: [Value] = []
|
|
77
|
+
var j = 0
|
|
78
|
+
while j < length(env.values) {
|
|
79
|
+
if j == i {
|
|
80
|
+
new_values = push(new_values, value)
|
|
81
|
+
} else {
|
|
82
|
+
new_values = push(new_values, env.values[j])
|
|
83
|
+
}
|
|
84
|
+
j = j + 1
|
|
85
|
+
}
|
|
86
|
+
return Environment { vars: env.vars, values: new_values, parent: env.parent }
|
|
87
|
+
}
|
|
88
|
+
i = i + 1
|
|
89
|
+
}
|
|
90
|
+
// Check parent scope
|
|
91
|
+
if env.parent != null {
|
|
92
|
+
var new_parent = env_set(env.parent, name, value)
|
|
93
|
+
return Environment { vars: env.vars, values: env.values, parent: new_parent }
|
|
94
|
+
}
|
|
95
|
+
// Not found, define locally
|
|
96
|
+
return env_define(env, name, value)
|
|
97
|
+
}
|
|
98
|
+
|
|
99
|
+
// ============================================================
|
|
100
|
+
// Expression Evaluation
|
|
101
|
+
// ============================================================
|
|
102
|
+
|
|
103
|
+
fn eval_expr(expr: Expr, env: Environment, runtime: Runtime) -> Value {
|
|
104
|
+
if expr.kind == "int" {
|
|
105
|
+
return Value { kind: "i32", val_i32: 42 } // TODO: actual int value from expr
|
|
106
|
+
} else if expr.kind == "float" {
|
|
107
|
+
return Value { kind: "f64", val_f64: 3.14 } // TODO: actual float value
|
|
108
|
+
} else if expr.kind == "string" {
|
|
109
|
+
return Value { kind: "string", val_string: expr.val_string }
|
|
110
|
+
} else if expr.kind == "bool" {
|
|
111
|
+
return Value { kind: "bool", val_bool: expr.val_bool }
|
|
112
|
+
} else if expr.kind == "ident" {
|
|
113
|
+
return env_get(env, expr.val_name)
|
|
114
|
+
} else if expr.kind == "array" {
|
|
115
|
+
var elements: [Value] = []
|
|
116
|
+
var i = 0
|
|
117
|
+
while i < length(expr.val_elements) {
|
|
118
|
+
var elem_val = eval_expr(expr.val_elements[i], env, runtime)
|
|
119
|
+
elements = push(elements, elem_val)
|
|
120
|
+
i = i + 1
|
|
121
|
+
}
|
|
122
|
+
return Value { kind: "array", val_array: elements }
|
|
123
|
+
} else if expr.kind == "binary" {
|
|
124
|
+
var left = eval_expr(expr.val_left, env, runtime)
|
|
125
|
+
var right = eval_expr(expr.val_right, env, runtime)
|
|
126
|
+
return eval_binary_op(expr.val_op, left, right)
|
|
127
|
+
} else if expr.kind == "unary" {
|
|
128
|
+
var operand = eval_expr(expr.val_expr, env, runtime)
|
|
129
|
+
return eval_unary_op(expr.val_op, operand)
|
|
130
|
+
} else if expr.kind == "call" {
|
|
131
|
+
// Function call - lookup function and execute
|
|
132
|
+
var args: [Value] = []
|
|
133
|
+
var i = 0
|
|
134
|
+
while i < length(expr.val_args) {
|
|
135
|
+
var arg_val = eval_expr(expr.val_args[i], env, runtime)
|
|
136
|
+
args = push(args, arg_val)
|
|
137
|
+
i = i + 1
|
|
138
|
+
}
|
|
139
|
+
return call_function(expr.val_name, args, env, runtime)
|
|
140
|
+
} else if expr.kind == "index" {
|
|
141
|
+
var array_val = eval_expr(expr.val_expr, env, runtime)
|
|
142
|
+
var index_val = eval_expr(expr.val_index, env, runtime)
|
|
143
|
+
if array_val.kind == "array" {
|
|
144
|
+
var idx = index_val.val_i32
|
|
145
|
+
if idx >= 0 && idx < length(array_val.val_array) {
|
|
146
|
+
return array_val.val_array[idx]
|
|
147
|
+
}
|
|
148
|
+
return Value { kind: "error", val_error: "Index out of bounds" }
|
|
149
|
+
}
|
|
150
|
+
return Value { kind: "error", val_error: "Cannot index non-array" }
|
|
151
|
+
} else if expr.kind == "if" {
|
|
152
|
+
var cond = eval_expr(expr.val_cond, env, runtime)
|
|
153
|
+
if is_truthy(cond) {
|
|
154
|
+
return eval_expr(expr.val_then_expr, env, runtime)
|
|
155
|
+
} else {
|
|
156
|
+
return eval_expr(expr.val_else_expr, env, runtime)
|
|
157
|
+
}
|
|
158
|
+
} else {
|
|
159
|
+
return Value { kind: "error", val_error: "Unknown expr: " + expr.kind }
|
|
160
|
+
}
|
|
161
|
+
}
|
|
162
|
+
|
|
163
|
+
fn eval_binary_op(op: str, left: Value, right: Value) -> Value {
|
|
164
|
+
if op == "+" {
|
|
165
|
+
if left.kind == "i32" && right.kind == "i32" {
|
|
166
|
+
return Value { kind: "i32", val_i32: left.val_i32 + right.val_i32 }
|
|
167
|
+
} else if left.kind == "string" {
|
|
168
|
+
var left_str = if left.kind == "string" { left.val_string } else { "" }
|
|
169
|
+
var right_str = if right.kind == "string" { right.val_string } else { "" }
|
|
170
|
+
return Value { kind: "string", val_string: left_str + right_str }
|
|
171
|
+
}
|
|
172
|
+
} else if op == "-" && left.kind == "i32" && right.kind == "i32" {
|
|
173
|
+
return Value { kind: "i32", val_i32: left.val_i32 - right.val_i32 }
|
|
174
|
+
} else if op == "*" && left.kind == "i32" && right.kind == "i32" {
|
|
175
|
+
return Value { kind: "i32", val_i32: left.val_i32 * right.val_i32 }
|
|
176
|
+
} else if op == "/" && left.kind == "i32" && right.kind == "i32" {
|
|
177
|
+
if right.val_i32 != 0 {
|
|
178
|
+
return Value { kind: "i32", val_i32: left.val_i32 / right.val_i32 }
|
|
179
|
+
}
|
|
180
|
+
return Value { kind: "error", val_error: "Division by zero" }
|
|
181
|
+
} else if op == "==" {
|
|
182
|
+
var equal = values_equal(left, right)
|
|
183
|
+
return Value { kind: "bool", val_bool: equal }
|
|
184
|
+
} else if op == "!=" {
|
|
185
|
+
var equal = values_equal(left, right)
|
|
186
|
+
return Value { kind: "bool", val_bool: !equal }
|
|
187
|
+
} else if op == "<" && left.kind == "i32" && right.kind == "i32" {
|
|
188
|
+
return Value { kind: "bool", val_bool: left.val_i32 < right.val_i32 }
|
|
189
|
+
} else if op == ">" && left.kind == "i32" && right.kind == "i32" {
|
|
190
|
+
return Value { kind: "bool", val_bool: left.val_i32 > right.val_i32 }
|
|
191
|
+
} else if op == "<=" && left.kind == "i32" && right.kind == "i32" {
|
|
192
|
+
return Value { kind: "bool", val_bool: left.val_i32 <= right.val_i32 }
|
|
193
|
+
} else if op == ">=" && left.kind == "i32" && right.kind == "i32" {
|
|
194
|
+
return Value { kind: "bool", val_bool: left.val_i32 >= right.val_i32 }
|
|
195
|
+
} else if op == "&&" {
|
|
196
|
+
return Value { kind: "bool", val_bool: is_truthy(left) && is_truthy(right) }
|
|
197
|
+
} else if op == "||" {
|
|
198
|
+
return Value { kind: "bool", val_bool: is_truthy(left) || is_truthy(right) }
|
|
199
|
+
}
|
|
200
|
+
return Value { kind: "error", val_error: "Unknown operator: " + op }
|
|
201
|
+
}
|
|
202
|
+
|
|
203
|
+
fn eval_unary_op(op: str, operand: Value) -> Value {
|
|
204
|
+
if op == "-" && operand.kind == "i32" {
|
|
205
|
+
return Value { kind: "i32", val_i32: 0 - operand.val_i32 }
|
|
206
|
+
} else if op == "!" {
|
|
207
|
+
return Value { kind: "bool", val_bool: !is_truthy(operand) }
|
|
208
|
+
}
|
|
209
|
+
return Value { kind: "error", val_error: "Unknown unary operator: " + op }
|
|
210
|
+
}
|
|
211
|
+
|
|
212
|
+
fn is_truthy(val: Value) -> bool {
|
|
213
|
+
if val.kind == "bool" {
|
|
214
|
+
return val.val_bool
|
|
215
|
+
} else if val.kind == "i32" {
|
|
216
|
+
return val.val_i32 != 0
|
|
217
|
+
} else if val.kind == "null" {
|
|
218
|
+
return false
|
|
219
|
+
}
|
|
220
|
+
return true
|
|
221
|
+
}
|
|
222
|
+
|
|
223
|
+
fn values_equal(left: Value, right: Value) -> bool {
|
|
224
|
+
if left.kind != right.kind {
|
|
225
|
+
return false
|
|
226
|
+
}
|
|
227
|
+
if left.kind == "i32" {
|
|
228
|
+
return left.val_i32 == right.val_i32
|
|
229
|
+
} else if left.kind == "string" {
|
|
230
|
+
return left.val_string == right.val_string
|
|
231
|
+
} else if left.kind == "bool" {
|
|
232
|
+
return left.val_bool == right.val_bool
|
|
233
|
+
} else if left.kind == "null" {
|
|
234
|
+
return true
|
|
235
|
+
}
|
|
236
|
+
return false
|
|
237
|
+
}
|
|
238
|
+
|
|
239
|
+
// ============================================================
|
|
240
|
+
// Statement Execution
|
|
241
|
+
// ============================================================
|
|
242
|
+
|
|
243
|
+
fn exec_stmt(stmt: Stmt, env: Environment, runtime: Runtime) -> Environment {
|
|
244
|
+
if stmt.kind == "expr" {
|
|
245
|
+
eval_expr(stmt.val_expr, env, runtime)
|
|
246
|
+
return env
|
|
247
|
+
} else if stmt.kind == "var" {
|
|
248
|
+
var value = eval_expr(stmt.val_value, env, runtime)
|
|
249
|
+
return env_define(env, stmt.val_name, value)
|
|
250
|
+
} else if stmt.kind == "let" {
|
|
251
|
+
var value = eval_expr(stmt.val_value, env, runtime)
|
|
252
|
+
return env_define(env, stmt.val_name, value)
|
|
253
|
+
} else if stmt.kind == "return" {
|
|
254
|
+
var value = eval_expr(stmt.val_value, env, runtime)
|
|
255
|
+
runtime.return_value = value
|
|
256
|
+
return env
|
|
257
|
+
} else if stmt.kind == "if" {
|
|
258
|
+
var cond = eval_expr(stmt.val_cond, env, runtime)
|
|
259
|
+
var new_env = env
|
|
260
|
+
if is_truthy(cond) {
|
|
261
|
+
var i = 0
|
|
262
|
+
while i < length(stmt.val_then_block) {
|
|
263
|
+
new_env = exec_stmt(stmt.val_then_block[i], new_env, runtime)
|
|
264
|
+
i = i + 1
|
|
265
|
+
}
|
|
266
|
+
} else {
|
|
267
|
+
var i = 0
|
|
268
|
+
while i < length(stmt.val_else_block) {
|
|
269
|
+
new_env = exec_stmt(stmt.val_else_block[i], new_env, runtime)
|
|
270
|
+
i = i + 1
|
|
271
|
+
}
|
|
272
|
+
}
|
|
273
|
+
return new_env
|
|
274
|
+
} else if stmt.kind == "while" {
|
|
275
|
+
var new_env = env
|
|
276
|
+
while is_truthy(eval_expr(stmt.val_cond, new_env, runtime)) {
|
|
277
|
+
var i = 0
|
|
278
|
+
while i < length(stmt.val_body) {
|
|
279
|
+
new_env = exec_stmt(stmt.val_body[i], new_env, runtime)
|
|
280
|
+
i = i + 1
|
|
281
|
+
}
|
|
282
|
+
}
|
|
283
|
+
return new_env
|
|
284
|
+
} else if stmt.kind == "for" {
|
|
285
|
+
var start = eval_expr(stmt.val_start, env, runtime)
|
|
286
|
+
var end = eval_expr(stmt.val_end, env, runtime)
|
|
287
|
+
var new_env = env
|
|
288
|
+
if start.kind == "i32" && end.kind == "i32" {
|
|
289
|
+
var idx = start.val_i32
|
|
290
|
+
while idx < end.val_i32 {
|
|
291
|
+
new_env = env_define(new_env, stmt.val_var, Value { kind: "i32", val_i32: idx })
|
|
292
|
+
var i = 0
|
|
293
|
+
while i < length(stmt.val_body) {
|
|
294
|
+
new_env = exec_stmt(stmt.val_body[i], new_env, runtime)
|
|
295
|
+
i = i + 1
|
|
296
|
+
}
|
|
297
|
+
idx = idx + 1
|
|
298
|
+
}
|
|
299
|
+
}
|
|
300
|
+
return new_env
|
|
301
|
+
} else if stmt.kind == "block" {
|
|
302
|
+
var new_env = env
|
|
303
|
+
var i = 0
|
|
304
|
+
while i < length(stmt.val_stmts) {
|
|
305
|
+
new_env = exec_stmt(stmt.val_stmts[i], new_env, runtime)
|
|
306
|
+
i = i + 1
|
|
307
|
+
}
|
|
308
|
+
return new_env
|
|
309
|
+
}
|
|
310
|
+
return env
|
|
311
|
+
}
|
|
312
|
+
|
|
313
|
+
// ============================================================
|
|
314
|
+
// Function Call
|
|
315
|
+
// ============================================================
|
|
316
|
+
|
|
317
|
+
fn call_function(name: str, args: [Value], env: Environment, runtime: Runtime) -> Value {
|
|
318
|
+
// TODO: Lookup function in runtime.functions array
|
|
319
|
+
// Execute function body with new environment
|
|
320
|
+
return Value { kind: "error", val_error: "Function not implemented: " + name }
|
|
321
|
+
}
|
|
322
|
+
|
|
323
|
+
// ============================================================
|
|
324
|
+
// Main Interpreter
|
|
325
|
+
// ============================================================
|
|
326
|
+
|
|
327
|
+
fn interpret(decls: [Decl]) -> Value {
|
|
328
|
+
var runtime = Runtime { globals: env_new(), functions: [], function_bodies: [], return_value: Value { kind: "null" }, break_flag: false, continue_flag: false }
|
|
329
|
+
var env = runtime.globals
|
|
330
|
+
|
|
331
|
+
// First pass: register all function declarations
|
|
332
|
+
var i = 0
|
|
333
|
+
while i < length(decls) {
|
|
334
|
+
if decls[i].kind == "fn" {
|
|
335
|
+
runtime.functions = push(runtime.functions, decls[i].val_name)
|
|
336
|
+
// Store function body - simplified
|
|
337
|
+
}
|
|
338
|
+
i = i + 1
|
|
339
|
+
}
|
|
340
|
+
|
|
341
|
+
// Second pass: execute declarations (mainly structs and function definitions)
|
|
342
|
+
var i = 0
|
|
343
|
+
while i < length(decls) {
|
|
344
|
+
if decls[i].kind == "struct" {
|
|
345
|
+
// Register struct type
|
|
346
|
+
}
|
|
347
|
+
i = i + 1
|
|
348
|
+
}
|
|
349
|
+
|
|
350
|
+
return Value { kind: "null" }
|
|
351
|
+
}
|
|
352
|
+
|
|
353
|
+
// ============================================================
|
|
354
|
+
// Test Entry Point
|
|
355
|
+
// ============================================================
|
|
356
|
+
|
|
357
|
+
fn test_interpreter() {
|
|
358
|
+
println("Interpreter initialized")
|
|
359
|
+
}
|
|
360
|
+
|
|
361
|
+
// test_interpreter()
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
// ============================================================
|
|
2
|
+
// FreeLang v4 Self-Hosting Lexer (Simplified)
|
|
3
|
+
// ============================================================
|
|
4
|
+
|
|
5
|
+
fn lex(source: str) -> str {
|
|
6
|
+
var result = "Lexing: "
|
|
7
|
+
var i = 0
|
|
8
|
+
while i < length(source) {
|
|
9
|
+
var c = char_at(source, i)
|
|
10
|
+
result = result + c
|
|
11
|
+
i = i + 1
|
|
12
|
+
}
|
|
13
|
+
return result
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
fn test_simple_lex() -> void {
|
|
17
|
+
var code = "var x = 42"
|
|
18
|
+
var tokens = lex(code)
|
|
19
|
+
println(tokens)
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
test_simple_lex()
|