Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
74 changes: 70 additions & 4 deletions .makim.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -85,9 +85,20 @@ groups:
type: string
required: true
run: |
import subprocess

for name in "${{ args.examples }}".split(","):
print(f" show tokens: {name} ".center(80, "="))
arx --show-tokens examples/@(name).x
result = subprocess.run(
["arx", "--show-tokens", f"examples/{name}.x"],
capture_output=True,
text=True,
check=True,
)
output = result.stdout.strip()
if not output:
raise RuntimeError(f"show-tokens produced no output for: {name}")
print(output)
show-ast:
help: Emit ast for input file
args:
Expand All @@ -96,9 +107,25 @@ groups:
type: string
required: true
run: |
import subprocess

for name in "${{ args.examples }}".split(","):
print(f" show ast: {name} ".center(80, "="))
arx --show-ast examples/@(name).x
result = subprocess.run(
["arx", "--show-ast", f"examples/{name}.x"],
capture_output=True,
text=True,
check=True,
)
output = result.stdout.strip()
if not output:
raise RuntimeError(f"show-ast produced no output for: {name}")
if output == "Block":
raise RuntimeError(
"show-ast regression: got only 'Block'. "
f"example={name}"
)
print(output)
show-llvm-ir:
help: Emit ast for input file
args:
Expand All @@ -107,9 +134,23 @@ groups:
type: string
required: true
run: |
import subprocess

for name in "${{ args.examples }}".split(","):
print(f" show llvm ir: {name} ".center(80, "="))
arx --show-llvm-ir examples/@(name).x
result = subprocess.run(
["arx", "--show-llvm-ir", f"examples/{name}.x"],
capture_output=True,
text=True,
check=True,
)
output = result.stdout.strip()
if "; ModuleID" not in output:
raise RuntimeError(
"show-llvm-ir output missing LLVM header for: "
f"{name}"
)
print(output)
emit-object:
help: Emit ast for input file
args:
Expand All @@ -118,9 +159,34 @@ groups:
type: string
required: true
run: |
import subprocess

from pathlib import Path

output_dir = Path("build/smoke")
output_dir.mkdir(parents=True, exist_ok=True)

for name in "${{ args.examples }}".split(","):
print(f" emit object: {name} ".center(80, "="))
arx examples/@(name).x
output_file = output_dir / name
if output_file.exists():
output_file.unlink()
subprocess.run(
[
"arx",
f"examples/{name}.x",
"--lib",
"--output-file",
str(output_file),
],
check=True,
)
if not output_file.exists() or output_file.stat().st_size == 0:
raise RuntimeError(
"emit-object did not produce a valid artifact for: "
f"{name}"
)
print(str(output_file))

docs:
tasks:
Expand Down
6 changes: 4 additions & 2 deletions AGENTS.md
Original file line number Diff line number Diff line change
Expand Up @@ -94,9 +94,11 @@ Current language behavior (from parser/lexer/tests/syntax manifest):
- Numeric literals: decimal integer/float (single `.` max)
- String/char/bool/none literals are supported
- Comments: `#` line comments
- Function definitions: `fn name(arg: type, ...)` followed by indented block
- Function definitions: `fn name(arg: type, ...) -> type` followed by indented
block
- Function arguments must be explicitly typed
- Extern definitions: `extern name(arg: type, ...)`
- Variable declarations must be explicitly typed (`var name: type`)
- Extern definitions: `extern name(arg: type, ...) -> type`
- Control flow: `if/else`, `while`, `for ... in (...)`, count-style `for`
- Range-style for header is `(start:end:step)` (tuple-style is rejected)
- Builtins: `cast(value, type)` and `print(expr)`
Expand Down
6 changes: 3 additions & 3 deletions docs/getting-started.md
Original file line number Diff line number Diff line change
Expand Up @@ -273,13 +273,13 @@ Variables are declared with `var`:
title: Variable example
summary: Shows var binding inside a function.
```
fn example():
fn example() -> i32:
```
title: example
summary: Binds a variable and computes a result.
```
var a = 10 in
a + 1
var a: i32 = 10
return a + 1
````

### Extern Functions
Expand Down
6 changes: 3 additions & 3 deletions docs/library/datatypes.md
Original file line number Diff line number Diff line change
@@ -1,13 +1,13 @@
# Data Types

Arx uses explicit type annotations for variables, function parameters, and
optional function return types.
function return types.

## Type Annotations

- Function parameters must always be typed.
- Function return type is optional. If omitted, current parser default is `f32`.
- Variable declarations can include an explicit type with `var name: type`.
- Function return type must always be explicit with `-> type`.
- Variable declarations must include an explicit type with `var name: type`.

````arx
```
Expand Down
6 changes: 3 additions & 3 deletions docs/library/docstrings.md
Original file line number Diff line number Diff line change
Expand Up @@ -45,7 +45,7 @@ Valid:
```
title: Module docs
```
fn main():
fn main() -> i32:
```
title: main
summary: Entry point for the module.
Expand All @@ -61,7 +61,7 @@ after `:` and the required newline/indentation.
Valid:

````text
fn main():
fn main() -> i32:
```
title: Function docs
summary: Function summary
Expand All @@ -72,7 +72,7 @@ fn main():
Invalid:

````text
fn main():
fn main() -> i32:
return 1
```
title: Too late
Expand Down
2 changes: 1 addition & 1 deletion docs/library/functions.md
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,7 @@ fn double(v: i32) -> i32:
```
return v * 2

fn main():
fn main() -> i32:
```
title: main
summary: Calls double with a constant input.
Expand Down
4 changes: 2 additions & 2 deletions docs/library/modules.md
Original file line number Diff line number Diff line change
Expand Up @@ -41,7 +41,7 @@ Valid:
```
title: Module docs
```
fn main():
fn main() -> i32:
```
title: main
summary: Entry point for the module.
Expand All @@ -55,7 +55,7 @@ Invalid (leading indentation before module docstring):
```
title: Module docs
```
fn main():
fn main() -> i32:
```
title: main
summary: Entry point for the module.
Expand Down
34 changes: 22 additions & 12 deletions src/arx/parser.py
Original file line number Diff line number Diff line change
Expand Up @@ -596,10 +596,14 @@ def parse_inline_var_declaration(self) -> astx.InlineVariableDeclaration:
name = cast(str, self.tokens.cur_tok.value)
self.tokens.get_next_token() # eat identifier

var_type: astx.DataType = astx.Float32()
if self._is_operator(":"):
self._consume_operator(":")
var_type = self.parse_type()
if not self._is_operator(":"):
raise ParserException(
"Parser: Expected type annotation for inline variable "
f"'{name}'."
)

self._consume_operator(":")
var_type = self.parse_type()

self._consume_operator("=")
value = self.parse_expression()
Expand All @@ -626,10 +630,13 @@ def parse_var_expr(self) -> astx.VariableDeclaration:
name = cast(str, self.tokens.cur_tok.value)
self.tokens.get_next_token() # eat identifier

var_type: astx.DataType = astx.Float32()
if self._is_operator(":"):
self._consume_operator(":")
var_type = self.parse_type()
if not self._is_operator(":"):
raise ParserException(
f"Parser: Expected type annotation for variable '{name}'."
)

self._consume_operator(":")
var_type = self.parse_type()

value: astx.Expr | None = None
if self._is_operator("="):
Expand Down Expand Up @@ -824,10 +831,13 @@ def parse_prototype(self, expect_colon: bool) -> astx.FunctionPrototype:

self._consume_operator(")")

ret_type: astx.DataType = astx.Float32()
if self._is_operator("->"):
self._consume_operator("->")
ret_type = self.parse_type()
if not self._is_operator("->"):
raise ParserException(
"Parser: Expected return type annotation with '->'."
)

self._consume_operator("->")
ret_type = self.parse_type()

if expect_colon:
self._consume_operator(":")
Expand Down
2 changes: 1 addition & 1 deletion tests/test_app_paths.py
Original file line number Diff line number Diff line change
Expand Up @@ -105,7 +105,7 @@ def test_arxio_file_and_stdin_loaders(
type: Path
"""
sample = tmp_path / "sample.x"
sample.write_text("fn main():\n return 1\n", encoding="utf-8")
sample.write_text("fn main() -> i32:\n return 1\n", encoding="utf-8")
ArxIO.file_to_buffer(str(sample))
assert "fn main()" in ArxIO.buffer.buffer

Expand Down
4 changes: 2 additions & 2 deletions tests/test_codegen_ast_output.py
Original file line number Diff line number Diff line change
Expand Up @@ -13,8 +13,8 @@
@pytest.mark.parametrize(
"code",
[
"fn main():\n return 0.0 + 1.0",
"fn main():\n return 1.0 + 2.0 * (3.0 - 2.0)",
"fn main() -> f32:\n return 0.0 + 1.0",
"fn main() -> f32:\n return 1.0 + 2.0 * (3.0 - 2.0)",
"fn main() -> i32:\n print(42)\n return 0",
"fn main() -> i32:\n print(3.5)\n return 0",
(
Expand Down
4 changes: 2 additions & 2 deletions tests/test_codegen_file_object.py
Original file line number Diff line number Diff line change
Expand Up @@ -21,8 +21,8 @@
@pytest.mark.parametrize(
"code",
[
"fn main():\n return 1.0 + 1.0",
"fn main():\n return 1.0 + 2.0 * (3.0 - 2.0)",
"fn main() -> f32:\n return 1.0 + 1.0",
"fn main() -> f32:\n return 1.0 + 2.0 * (3.0 - 2.0)",
# "fn main():\n if (1 < 2):\n return 3\nelse:\n return 2\n",
],
)
Expand Down
Loading
Loading