Switch to curly braces for scoping instead of indentation
This commit is contained in:
parent
9337490f5b
commit
893aa5d979
21 changed files with 692 additions and 728 deletions
|
|
@ -187,7 +187,7 @@ int main(int argc, char ** argv)
|
||||||
if (dump_ast)
|
if (dump_ast)
|
||||||
{
|
{
|
||||||
std::cout << "Input file " << filenames.back() << " AST dump:\n\n";
|
std::cout << "Input file " << filenames.back() << " AST dump:\n\n";
|
||||||
if (auto function_definition = std::get_if<ast::function_definition>(parsed.back().get()))
|
if (auto function_definition = std::get_if<ast::function_definition>(root.get()))
|
||||||
ast::print(std::cout, *function_definition->statements);
|
ast::print(std::cout, *function_definition->statements);
|
||||||
std::cout << "\n" << std::flush;
|
std::cout << "\n" << std::flush;
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -4,81 +4,92 @@ import components
|
||||||
import ecs
|
import ecs
|
||||||
|
|
||||||
const x = 10s // deduced type i16
|
const x = 10s // deduced type i16
|
||||||
var y = 14u // deduced type u32
|
mut y = 14u // deduced type u32
|
||||||
var z: f64 = 3.14l
|
mut z: f64 = 3.14l
|
||||||
|
|
||||||
func fma(x: f32, y: f32, z: f32) -> f32:
|
func fma(x: f32, y: f32, z: f32) -> f32 {
|
||||||
return x * y + z
|
return x * y + z
|
||||||
|
}
|
||||||
|
|
||||||
struct vec2:
|
struct vec2 {
|
||||||
x: f32
|
x: f32
|
||||||
y: f32
|
y: f32
|
||||||
|
}
|
||||||
|
|
||||||
// pass by value
|
// pass by value
|
||||||
func length(v: vec2) -> f32:
|
func length(v: vec2) -> f32 {
|
||||||
return math.sqrt(v.x * v.x + v.y * v.y)
|
return math.sqrt(v.x * v.x + v.y * v.y)
|
||||||
|
}
|
||||||
|
|
||||||
// return type deduced as u64
|
func merge(x: u32, y: u32) -> u64 {
|
||||||
func merge(x: u32, y: u32):
|
|
||||||
return (x as u64) or ((y as u64) << 32)
|
return (x as u64) or ((y as u64) << 32)
|
||||||
|
}
|
||||||
|
|
||||||
var v = vec2(10, 20)
|
mut v = vec2(10, 20)
|
||||||
length(v)
|
length(v)
|
||||||
|
|
||||||
// can be called using method syntax
|
// can be called using method syntax
|
||||||
v.length()
|
v.length()
|
||||||
|
|
||||||
// function pointers
|
// function pointers
|
||||||
var my_func = fma // deduced type (f32, f32, f32) -> f32
|
mut my_func = fma // deduced type (f32, f32, f32) -> f32
|
||||||
|
|
||||||
// pass by reference/pointer with *
|
// pass by reference/pointer with *
|
||||||
// TODO: const pointer?
|
// TODO: const pointer?
|
||||||
func my_system(event: events.update, position: *components.position, velocity: *components.velocity):
|
func my_system(event: events.update, position: components.position mut*, velocity: components.velocity*) {
|
||||||
position += event.dt * velocity
|
position += event.dt * velocity
|
||||||
|
}
|
||||||
|
|
||||||
func attach(dispatcher: *ecs.dispatcher):
|
func attach(dispatcher: ecs.dispatcher*) {
|
||||||
// TODO: how does it work? C++-style variadic templates? Oh no...
|
// TODO: how does it work? C++-style variadic templates? Oh no...
|
||||||
dispatcher.system(my_system)
|
dispatcher.system(my_system)
|
||||||
|
}
|
||||||
|
|
||||||
// objects with methods
|
// objects with methods
|
||||||
struct rectangle:
|
struct rectangle {
|
||||||
width: i32
|
width: i32
|
||||||
height: i32
|
height: i32
|
||||||
|
}
|
||||||
|
|
||||||
func extend(r: &rectangle, size: i32):
|
func extend(r: rectangle mut*, size: i32) {
|
||||||
r.width += size
|
r.width += size
|
||||||
r.height += size
|
r.height += size
|
||||||
|
}
|
||||||
|
|
||||||
var r = rectangle(10, 12)
|
mut r = rectangle(10, 12)
|
||||||
r.extend(5)
|
r.extend(5)
|
||||||
|
|
||||||
// named initializers
|
// named initializers
|
||||||
var r2 = rectangle(width = 20, height = 30)
|
mut r2 = rectangle(width = 20, height = 30)
|
||||||
|
|
||||||
// regular pointers
|
// regular pointers
|
||||||
var ptr: *i32 = null
|
mut ptr: i32* = null
|
||||||
var x = 15
|
mut x = 15
|
||||||
ptr = &x
|
ptr = &x
|
||||||
|
|
||||||
// field/method access using pointers is the same as with values
|
// field/method access using pointers is the same as with values
|
||||||
var sptr: *rectangle = &r
|
mut sptr: rectangle mut* = &r
|
||||||
r.width *= 2
|
r.width *= 2
|
||||||
|
|
||||||
// simple generics
|
// simple generics
|
||||||
struct array(T):
|
struct array(T) {
|
||||||
data: *T
|
data: *T
|
||||||
size: u64
|
size: u64
|
||||||
|
}
|
||||||
|
|
||||||
// TODO: constructors? destructors?
|
// TODO: constructors? destructors?
|
||||||
func new(self: array(T), size: u64):
|
func new(self: array(T), size: u64) {
|
||||||
return array(T)(data = mem.alloc(size * sizeof(T)), size = size)
|
return array(T)(data = mem.alloc(size * sizeof(T)), size = size)
|
||||||
|
}
|
||||||
|
|
||||||
// TODO: static arrays?
|
// TODO: static arrays?
|
||||||
// TODO: move-only types? alloc returns smth like unique ptr?
|
// TODO: move-only types? alloc returns smth like unique ptr?
|
||||||
|
|
||||||
struct kvpair(K, V):
|
struct kvpair(K, V) {
|
||||||
key: K
|
key: K
|
||||||
value: V
|
value: V
|
||||||
|
}
|
||||||
|
|
||||||
struct arraymap(K, V):
|
struct arraymap(K, V) {
|
||||||
values: array(kvpair(K, V))
|
values: array(kvpair(K, V))
|
||||||
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,7 +1,8 @@
|
||||||
foreign func sin(x: f64) -> f64
|
foreign func sin(x: f64) -> f64
|
||||||
foreign func cos(x: f64) -> f64
|
foreign func cos(x: f64) -> f64
|
||||||
|
|
||||||
func test(x: f64) -> f64:
|
func test(x: f64) -> f64 {
|
||||||
let s = sin(x)
|
let s = sin(x)
|
||||||
let c = cos(x)
|
let c = cos(x)
|
||||||
return s * s + c * c
|
return s * s + c * c
|
||||||
|
}
|
||||||
|
|
@ -1,40 +1,48 @@
|
||||||
func print(c: u8):
|
func print(c: u8) {
|
||||||
foreign func putchar(c: i32) -> i32
|
foreign func putchar(c: i32) -> i32
|
||||||
putchar(c as i32)
|
putchar(c as i32)
|
||||||
|
}
|
||||||
|
|
||||||
func print_i32(x: i32):
|
func print_i32(x: i32) {
|
||||||
if x < 0:
|
if x < 0 {
|
||||||
print('-')
|
print('-')
|
||||||
print_i32(-x)
|
print_i32(-x)
|
||||||
return
|
return
|
||||||
if x >= 10:
|
}
|
||||||
|
if x >= 10 {
|
||||||
print_i32(x / 10)
|
print_i32(x / 10)
|
||||||
|
}
|
||||||
print('0' + (x % 10 as u8))
|
print('0' + (x % 10 as u8))
|
||||||
|
}
|
||||||
|
|
||||||
func print_f32(x: f32):
|
func print_f32(x: f32) {
|
||||||
if x < 0.0:
|
if x < 0.0 {
|
||||||
print('-')
|
print('-')
|
||||||
print_f32(-x)
|
print_f32(-x)
|
||||||
return
|
return
|
||||||
|
}
|
||||||
foreign func floorf(x: f32) -> f32
|
foreign func floorf(x: f32) -> f32
|
||||||
let floor = floorf(x) as i32
|
let floor = floorf(x) as i32
|
||||||
print_i32(floor)
|
print_i32(floor)
|
||||||
print('.')
|
print('.')
|
||||||
mut y = x - (floor as f32)
|
mut y = x - (floor as f32)
|
||||||
mut i = 0
|
mut i = 0
|
||||||
while i < 5:
|
while i < 5 {
|
||||||
y = y * 10.0
|
y = y * 10.0
|
||||||
let yfloor = floorf(y) as i32
|
let yfloor = floorf(y) as i32
|
||||||
print('0' + (yfloor as u8))
|
print('0' + (yfloor as u8))
|
||||||
y = y - (yfloor as f32)
|
y = y - (yfloor as f32)
|
||||||
i = i + 1
|
i = i + 1
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
struct vec3:
|
struct vec3 {
|
||||||
x: f32
|
x: f32
|
||||||
y: f32
|
y: f32
|
||||||
z: f32
|
z: f32
|
||||||
|
}
|
||||||
|
|
||||||
func print_vec3(v: vec3):
|
func print_vec3(v: vec3) {
|
||||||
print('(')
|
print('(')
|
||||||
print_f32(v.x)
|
print_f32(v.x)
|
||||||
print(',')
|
print(',')
|
||||||
|
|
@ -42,31 +50,39 @@ func print_vec3(v: vec3):
|
||||||
print(',')
|
print(',')
|
||||||
print_f32(v.z)
|
print_f32(v.z)
|
||||||
print(')')
|
print(')')
|
||||||
|
}
|
||||||
|
|
||||||
func dot(a: vec3, b: vec3) -> f32:
|
func dot(a: vec3, b: vec3) -> f32 {
|
||||||
return a.x * b.x + a.y * b.y + a.z * b.z
|
return a.x * b.x + a.y * b.y + a.z * b.z
|
||||||
|
}
|
||||||
|
|
||||||
func add(a: vec3, b: vec3) -> vec3:
|
func add(a: vec3, b: vec3) -> vec3 {
|
||||||
return vec3(a.x + b.x, a.y + b.y, a.z + b.z)
|
return vec3(a.x + b.x, a.y + b.y, a.z + b.z)
|
||||||
|
}
|
||||||
|
|
||||||
func mult(a: vec3, b: f32) -> vec3:
|
func mult(a: vec3, b: f32) -> vec3 {
|
||||||
return vec3(a.x * b, a.y * b, a.z * b)
|
return vec3(a.x * b, a.y * b, a.z * b)
|
||||||
|
}
|
||||||
|
|
||||||
func normalized(v: vec3) -> vec3:
|
func normalized(v: vec3) -> vec3 {
|
||||||
foreign func sqrtf(x: f32) -> f32
|
foreign func sqrtf(x: f32) -> f32
|
||||||
return mult(v, 1.0 / sqrtf(dot(v, v)))
|
return mult(v, 1.0 / sqrtf(dot(v, v)))
|
||||||
|
}
|
||||||
|
|
||||||
struct ray:
|
struct ray {
|
||||||
origin: vec3
|
origin: vec3
|
||||||
direction: vec3
|
direction: vec3
|
||||||
|
}
|
||||||
|
|
||||||
func intersect_plane(ray: ray, normal: vec3, value: f32) -> f32:
|
func intersect_plane(ray: ray, normal: vec3, value: f32) -> f32 {
|
||||||
return (value - dot(ray.origin, normal)) / dot(ray.direction, normal)
|
return (value - dot(ray.origin, normal)) / dot(ray.direction, normal)
|
||||||
|
}
|
||||||
|
|
||||||
func test() -> i32[3]:
|
func test() -> i32[3] {
|
||||||
return [70, 60, 50]
|
return [70, 60, 50]
|
||||||
|
}
|
||||||
|
|
||||||
func print_i32_3(a: i32[3]):
|
func print_i32_3(a: i32[3]) {
|
||||||
print('[')
|
print('[')
|
||||||
print_i32(a[0])
|
print_i32(a[0])
|
||||||
print(',')
|
print(',')
|
||||||
|
|
@ -74,6 +90,7 @@ func print_i32_3(a: i32[3]):
|
||||||
print(',')
|
print(',')
|
||||||
print_i32(a[2])
|
print_i32(a[2])
|
||||||
print(']')
|
print(']')
|
||||||
|
}
|
||||||
|
|
||||||
mut a = [1, 2, 3]
|
mut a = [1, 2, 3]
|
||||||
a = test()
|
a = test()
|
||||||
|
|
|
||||||
|
|
@ -1,11 +1,13 @@
|
||||||
func print(c: u8):
|
func print(c: u8) {
|
||||||
foreign func putchar(c: i32) -> i32
|
foreign func putchar(c: i32) -> i32
|
||||||
putchar(c as i32)
|
putchar(c as i32)
|
||||||
|
}
|
||||||
|
|
||||||
func test() -> i32:
|
func test() -> i32 {
|
||||||
global mut x = 0
|
global mut x = 0
|
||||||
x += 1
|
x += 1
|
||||||
return x
|
return x
|
||||||
|
}
|
||||||
|
|
||||||
print('0' + (test() as u8))
|
print('0' + (test() as u8))
|
||||||
print('0' + (test() as u8))
|
print('0' + (test() as u8))
|
||||||
|
|
|
||||||
|
|
@ -1,32 +1,37 @@
|
||||||
foreign func putchar(c: i32) -> i32
|
func print(c: u8) {
|
||||||
|
foreign func putchar(c: i32) -> i32
|
||||||
func print(c: u8):
|
|
||||||
putchar(c as i32)
|
putchar(c as i32)
|
||||||
|
}
|
||||||
|
|
||||||
func mandelbrot():
|
func mandelbrot() {
|
||||||
let width = 120
|
let width = 120
|
||||||
let height = 40
|
let height = 40
|
||||||
mut y = 0
|
mut y = 0
|
||||||
while y < height:
|
while y < height {
|
||||||
mut x = 0
|
mut x = 0
|
||||||
while x < width:
|
while x < width {
|
||||||
let cx = (x as f32 + 0.5) / (width as f32) * 2.5 - 2.0
|
let cx = (x as f32 + 0.5) / (width as f32) * 2.5 - 2.0
|
||||||
let cy = (y as f32 + 0.5) / (height as f32) * 2.0 - 1.0
|
let cy = (y as f32 + 0.5) / (height as f32) * 2.0 - 1.0
|
||||||
mut tx = 0.0
|
mut tx = 0.0
|
||||||
mut ty = 0.0
|
mut ty = 0.0
|
||||||
mut i = 0
|
mut i = 0
|
||||||
while i < 100 && (tx * tx + ty * ty < 4.0):
|
while i < 100 && (tx * tx + ty * ty < 4.0) {
|
||||||
let newx = tx * tx - ty * ty + cx
|
let newx = tx * tx - ty * ty + cx
|
||||||
ty = 2.0 * tx * ty + cy
|
ty = 2.0 * tx * ty + cy
|
||||||
tx = newx
|
tx = newx
|
||||||
i = i + 1
|
i = i + 1
|
||||||
if i == 100:
|
}
|
||||||
|
if i == 100 {
|
||||||
print('X')
|
print('X')
|
||||||
else:
|
} else {
|
||||||
print(' ')
|
print(' ')
|
||||||
|
}
|
||||||
|
|
||||||
x = x + 1
|
x = x + 1
|
||||||
|
}
|
||||||
y = y + 1
|
y = y + 1
|
||||||
print('\n')
|
print('\n')
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
mandelbrot()
|
mandelbrot()
|
||||||
|
|
|
||||||
File diff suppressed because it is too large
Load diff
|
|
@ -1,11 +1,15 @@
|
||||||
func g() -> u16:
|
func g() -> u16 {
|
||||||
return g()
|
return g()
|
||||||
|
}
|
||||||
|
|
||||||
func h() -> bool:
|
func h() -> bool {
|
||||||
return h()
|
return h()
|
||||||
|
}
|
||||||
|
|
||||||
func test_and() -> u16:
|
func test_and() -> u16 {
|
||||||
return 0us && g()
|
return 0us && g()
|
||||||
|
}
|
||||||
|
|
||||||
func test_or() -> u16:
|
func test_or() -> u16 {
|
||||||
return 65535us || g()
|
return 65535us || g()
|
||||||
|
}
|
||||||
|
|
@ -1,10 +1,13 @@
|
||||||
struct vec2f:
|
struct vec2f {
|
||||||
x: f32
|
x: f32
|
||||||
y: f32
|
y: f32
|
||||||
|
}
|
||||||
|
|
||||||
struct body:
|
struct body {
|
||||||
position: vec2f
|
position: vec2f
|
||||||
rotation: f32
|
rotation: f32
|
||||||
|
}
|
||||||
|
|
||||||
func move_x(b: body mut*, delta: f32):
|
func move_x(b: body mut*, delta: f32) {
|
||||||
(*b).position.x = (*b).position.x + delta
|
b.position.x = b.position.x + delta
|
||||||
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,11 +1,13 @@
|
||||||
// Vectors
|
// Vectors
|
||||||
|
|
||||||
struct vec2:
|
struct vec2 {
|
||||||
x : f32
|
x : f32
|
||||||
y : f32
|
y : f32
|
||||||
|
}
|
||||||
|
|
||||||
func add(a : vec2, b : vec2) -> vec2:
|
func add(a : vec2, b : vec2) -> vec2 {
|
||||||
return vec2(a.x + b.x, a.y + b.y)
|
return vec2(a.x + b.x, a.y + b.y)
|
||||||
|
}
|
||||||
|
|
||||||
mut v = add(vec2(1.0, 2.0), vec2(3.0, 4.0))
|
mut v = add(vec2(1.0, 2.0), vec2(3.0, 4.0))
|
||||||
v.x = -v.x
|
v.x = -v.x
|
||||||
|
|
@ -13,34 +15,39 @@ v.y = -v.y
|
||||||
|
|
||||||
// Factorial
|
// Factorial
|
||||||
|
|
||||||
func factorial(n : u32) -> u32:
|
func factorial(n : u32) -> u32 {
|
||||||
if n == 0u:
|
if n == 0u { return 1u }
|
||||||
return 1u
|
|
||||||
return n * factorial(n - 1u)
|
return n * factorial(n - 1u)
|
||||||
|
}
|
||||||
|
|
||||||
let factorial10 = factorial(10u)
|
let factorial10 = factorial(10u)
|
||||||
|
|
||||||
// Fibonacci
|
// Fibonacci
|
||||||
func fib(n : u32) -> u32:
|
func fib(n : u32) -> u32 {
|
||||||
// Slow implementation with
|
// Slow implementation with
|
||||||
// exponentially-growing recursion tree
|
// exponentially-growing recursion tree
|
||||||
if n == 0u | n == 1u:
|
if n == 0u | n == 1u {
|
||||||
return n // base case
|
// Base case
|
||||||
|
return n
|
||||||
|
}
|
||||||
return fib(n - 1u) + fib(n - 2u)
|
return fib(n - 1u) + fib(n - 2u)
|
||||||
|
}
|
||||||
|
|
||||||
let fib10 = fib(10u)
|
let fib10 = fib(10u)
|
||||||
|
|
||||||
|
|
||||||
func h() -> u32:
|
func h() -> u32 {
|
||||||
return 0u
|
return 0u
|
||||||
|
}
|
||||||
|
|
||||||
func f() -> u32:
|
func f() -> u32 {
|
||||||
return h()
|
return h()
|
||||||
|
}
|
||||||
|
|
||||||
func g() -> u32:
|
func g() -> u32 {
|
||||||
func h() -> u32:
|
func h() -> u32 { return 1u }
|
||||||
return 1u
|
|
||||||
return f()
|
return f()
|
||||||
|
}
|
||||||
|
|
||||||
// Should equal 0u, but equals 1u due to an error in
|
// Should equal 0u, but equals 1u due to an error in
|
||||||
// how the interpreter resolves functions & variables
|
// how the interpreter resolves functions & variables
|
||||||
|
|
|
||||||
|
|
@ -20,29 +20,6 @@ namespace pslang::ast
|
||||||
ast::location location;
|
ast::location location;
|
||||||
};
|
};
|
||||||
|
|
||||||
using pre_statement_impl = std::variant<
|
|
||||||
expression_ptr,
|
|
||||||
assignment,
|
|
||||||
variable_declaration,
|
|
||||||
if_block,
|
|
||||||
else_block,
|
|
||||||
else_if_block,
|
|
||||||
while_block,
|
|
||||||
break_statement,
|
|
||||||
continue_statement,
|
|
||||||
function_definition,
|
|
||||||
foreign_function_declaration,
|
|
||||||
return_statement,
|
|
||||||
field_definition,
|
|
||||||
struct_definition
|
|
||||||
>;
|
|
||||||
|
|
||||||
struct pre_statement
|
|
||||||
: pre_statement_impl
|
|
||||||
{
|
|
||||||
using pre_statement_impl::pre_statement_impl;
|
|
||||||
};
|
|
||||||
|
|
||||||
using statement_impl = std::variant<
|
using statement_impl = std::variant<
|
||||||
expression_ptr,
|
expression_ptr,
|
||||||
assignment,
|
assignment,
|
||||||
|
|
@ -63,7 +40,6 @@ namespace pslang::ast
|
||||||
using statement_impl::statement_impl;
|
using statement_impl::statement_impl;
|
||||||
};
|
};
|
||||||
|
|
||||||
location get_location(pre_statement const & statement);
|
|
||||||
location get_location(statement const & statement);
|
location get_location(statement const & statement);
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -6,23 +6,15 @@
|
||||||
namespace pslang::ast
|
namespace pslang::ast
|
||||||
{
|
{
|
||||||
|
|
||||||
struct pre_statement;
|
|
||||||
struct statement;
|
struct statement;
|
||||||
|
|
||||||
using pre_statement_ptr = std::shared_ptr<pre_statement>;
|
|
||||||
using statement_ptr = std::shared_ptr<statement>;
|
using statement_ptr = std::shared_ptr<statement>;
|
||||||
|
|
||||||
struct pre_statement_list
|
|
||||||
{
|
|
||||||
std::vector<pre_statement_ptr> statements;
|
|
||||||
};
|
|
||||||
|
|
||||||
struct statement_list
|
struct statement_list
|
||||||
{
|
{
|
||||||
std::vector<statement_ptr> statements;
|
std::vector<statement_ptr> statements;
|
||||||
};
|
};
|
||||||
|
|
||||||
using pre_statement_list_ptr = std::shared_ptr<pre_statement_list>;
|
|
||||||
using statement_list_ptr = std::shared_ptr<statement_list>;
|
using statement_list_ptr = std::shared_ptr<statement_list>;
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -22,11 +22,6 @@ namespace pslang::ast
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
location get_location(pre_statement const & statement)
|
|
||||||
{
|
|
||||||
return std::visit(get_location_visitor{}, statement);
|
|
||||||
}
|
|
||||||
|
|
||||||
location get_location(statement const & statement)
|
location get_location(statement const & statement)
|
||||||
{
|
{
|
||||||
return std::visit(get_location_visitor{}, statement);
|
return std::visit(get_location_visitor{}, statement);
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,6 @@
|
||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
#include <pslang/parser/indented_statement.hpp>
|
#include <pslang/ast/statement_fwd.hpp>
|
||||||
|
|
||||||
namespace pslang::ast
|
namespace pslang::ast
|
||||||
{
|
{
|
||||||
|
|
@ -15,7 +15,7 @@ namespace pslang::parser
|
||||||
struct context
|
struct context
|
||||||
{
|
{
|
||||||
ast::location & location;
|
ast::location & location;
|
||||||
indented_statement_list & result;
|
ast::statement_list_ptr & result;
|
||||||
};
|
};
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
||||||
10
libs/parser/include/pslang/parser/finalize.hpp
Normal file
10
libs/parser/include/pslang/parser/finalize.hpp
Normal file
|
|
@ -0,0 +1,10 @@
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <pslang/ast/statement_fwd.hpp>
|
||||||
|
|
||||||
|
namespace pslang::parser
|
||||||
|
{
|
||||||
|
|
||||||
|
ast::statement_list_ptr finalize(ast::statement_list_ptr statements);
|
||||||
|
|
||||||
|
}
|
||||||
|
|
@ -1,23 +0,0 @@
|
||||||
#pragma once
|
|
||||||
|
|
||||||
#include <pslang/ast/statement_fwd.hpp>
|
|
||||||
|
|
||||||
#include <vector>
|
|
||||||
|
|
||||||
namespace pslang::parser
|
|
||||||
{
|
|
||||||
|
|
||||||
struct indented_statement
|
|
||||||
{
|
|
||||||
std::size_t indentation;
|
|
||||||
ast::pre_statement_ptr statement;
|
|
||||||
};
|
|
||||||
|
|
||||||
struct indented_statement_list
|
|
||||||
{
|
|
||||||
std::vector<indented_statement> statements;
|
|
||||||
};
|
|
||||||
|
|
||||||
ast::statement_list_ptr finalize(indented_statement_list statements);
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
@ -19,7 +19,7 @@ using bp = ::pslang::parser::bison::parser;
|
||||||
ctx.location.step();
|
ctx.location.step();
|
||||||
%}
|
%}
|
||||||
|
|
||||||
[ ]+ { ctx.location.step(); }
|
[ \r\t]+ { ctx.location.step(); }
|
||||||
|
|
||||||
"//"[^\n]* { return bp::make_comment(ctx.location); }
|
"//"[^\n]* { return bp::make_comment(ctx.location); }
|
||||||
|
|
||||||
|
|
@ -60,7 +60,6 @@ f64 { return bp::make_f64(ctx.location); }
|
||||||
[a-zA-Z_]+[a-zA-Z0-9_]* { return bp::make_name(yytext, ctx.location); }
|
[a-zA-Z_]+[a-zA-Z0-9_]* { return bp::make_name(yytext, ctx.location); }
|
||||||
|
|
||||||
"\n" { auto old_location = ctx.location; ctx.location.move_lines(1); return bp::make_newline(old_location); }
|
"\n" { auto old_location = ctx.location; ctx.location.move_lines(1); return bp::make_newline(old_location); }
|
||||||
"\t" { return bp::make_indent(ctx.location); }
|
|
||||||
"=" { return bp::make_assignment(ctx.location); }
|
"=" { return bp::make_assignment(ctx.location); }
|
||||||
":" { return bp::make_colon(ctx.location); }
|
":" { return bp::make_colon(ctx.location); }
|
||||||
"," { return bp::make_comma(ctx.location); }
|
"," { return bp::make_comma(ctx.location); }
|
||||||
|
|
@ -69,6 +68,8 @@ f64 { return bp::make_f64(ctx.location); }
|
||||||
")" { return bp::make_rparen(ctx.location); }
|
")" { return bp::make_rparen(ctx.location); }
|
||||||
"[" { return bp::make_lbracket(ctx.location); }
|
"[" { return bp::make_lbracket(ctx.location); }
|
||||||
"]" { return bp::make_rbracket(ctx.location); }
|
"]" { return bp::make_rbracket(ctx.location); }
|
||||||
|
"{" { return bp::make_lbrace(ctx.location); }
|
||||||
|
"}" { return bp::make_rbrace(ctx.location); }
|
||||||
"+=" { return bp::make_plus_assignment(ctx.location); }
|
"+=" { return bp::make_plus_assignment(ctx.location); }
|
||||||
"-=" { return bp::make_minus_assignment(ctx.location); }
|
"-=" { return bp::make_minus_assignment(ctx.location); }
|
||||||
"*=" { return bp::make_asterisk_assignment(ctx.location); }
|
"*=" { return bp::make_asterisk_assignment(ctx.location); }
|
||||||
|
|
|
||||||
|
|
@ -20,7 +20,6 @@
|
||||||
|
|
||||||
%code requires {
|
%code requires {
|
||||||
|
|
||||||
#include <pslang/parser/indented_statement.hpp>
|
|
||||||
#include <pslang/ast/statement.hpp>
|
#include <pslang/ast/statement.hpp>
|
||||||
|
|
||||||
namespace pslang::parser {
|
namespace pslang::parser {
|
||||||
|
|
@ -75,8 +74,7 @@ template <typename T>
|
||||||
%define api.token.prefix {tok_}
|
%define api.token.prefix {tok_}
|
||||||
|
|
||||||
%token newline "newline"
|
%token newline "newline"
|
||||||
%token indent "indentation"
|
%token comment "comment"
|
||||||
%token comment
|
|
||||||
%token assignment "="
|
%token assignment "="
|
||||||
%token colon ":"
|
%token colon ":"
|
||||||
%token comma ","
|
%token comma ","
|
||||||
|
|
@ -85,6 +83,8 @@ template <typename T>
|
||||||
%token rparen ")"
|
%token rparen ")"
|
||||||
%token lbracket "["
|
%token lbracket "["
|
||||||
%token rbracket "]"
|
%token rbracket "]"
|
||||||
|
%token lbrace "{"
|
||||||
|
%token rbrace "}"
|
||||||
%token plus "+"
|
%token plus "+"
|
||||||
%token minus "-"
|
%token minus "-"
|
||||||
%token asterisk "*"
|
%token asterisk "*"
|
||||||
|
|
@ -184,10 +184,12 @@ template <typename T>
|
||||||
%precedence else
|
%precedence else
|
||||||
%precedence lbracket
|
%precedence lbracket
|
||||||
|
|
||||||
%type <indented_statement_list> indented_statement_list
|
%type <ast::statement_list> statement_list
|
||||||
%type <indented_statement> statement_line
|
%type <ast::statement_list_ptr> statement_block
|
||||||
%type <std::size_t> indentation
|
%type <ast::statement> statement_line
|
||||||
%type <ast::pre_statement> statement
|
%type <ast::statement> statement
|
||||||
|
%type <ast::if_chain> if_chain
|
||||||
|
%type <ast::if_chain::block> single_if
|
||||||
%type <std::vector<ast::function_declaration::argument>> function_declaration_argument_list
|
%type <std::vector<ast::function_declaration::argument>> function_declaration_argument_list
|
||||||
%type <std::vector<ast::function_declaration::argument>> nonempty_function_declaration_argument_list
|
%type <std::vector<ast::function_declaration::argument>> nonempty_function_declaration_argument_list
|
||||||
%type <ast::function_declaration::argument> function_declaration_single_argument
|
%type <ast::function_declaration::argument> function_declaration_single_argument
|
||||||
|
|
@ -199,6 +201,8 @@ template <typename T>
|
||||||
%type <types::primitive_type> primitive_type
|
%type <types::primitive_type> primitive_type
|
||||||
%type <std::vector<ast::type_ptr>> function_paren_type_list
|
%type <std::vector<ast::type_ptr>> function_paren_type_list
|
||||||
%type <std::vector<ast::type_ptr>> two_or_more_type_list
|
%type <std::vector<ast::type_ptr>> two_or_more_type_list
|
||||||
|
%type <std::vector<ast::field_definition>> field_definition_list
|
||||||
|
%type <ast::field_definition> field_definition
|
||||||
%type <ast::expression> expression
|
%type <ast::expression> expression
|
||||||
%type <ast::expression> postfix_expression
|
%type <ast::expression> postfix_expression
|
||||||
%type <ast::expression> base_expression
|
%type <ast::expression> base_expression
|
||||||
|
|
@ -209,27 +213,26 @@ template <typename T>
|
||||||
%%
|
%%
|
||||||
|
|
||||||
module
|
module
|
||||||
: indented_statement_list end { ctx.result = $1; }
|
: statement_list end { ctx.result = std::make_unique<ast::statement_list>($1); }
|
||||||
;
|
;
|
||||||
|
|
||||||
indented_statement_list
|
statement_list
|
||||||
: statement_line { indented_statement_list tmp; tmp.statements.push_back(std::move($1)); $$ = std::move(tmp); }
|
: statement_line { ast::statement_list tmp; tmp.statements.push_back(std::make_unique<ast::statement>($1)); $$ = std::move(tmp); }
|
||||||
| empty_line { $$ = {}; }
|
| empty_line { $$ = {}; }
|
||||||
| indented_statement_list newline statement_line { auto tmp = $1; tmp.statements.push_back(std::move($3)); $$ = std::move(tmp); }
|
| statement_list newline statement_line { auto tmp = $1; tmp.statements.push_back(std::make_unique<ast::statement>($3)); $$ = std::move(tmp); }
|
||||||
| indented_statement_list newline empty_line { $$ = $1; }
|
| statement_list newline empty_line { $$ = $1; }
|
||||||
|
;
|
||||||
|
|
||||||
|
statement_block
|
||||||
|
: lbrace statement_list rbrace { $$ = std::make_unique<ast::statement_list>($2); }
|
||||||
;
|
;
|
||||||
|
|
||||||
statement_line
|
statement_line
|
||||||
: indentation statement optional_comment { $$ = indented_statement{$1, std::make_unique<ast::pre_statement>($2)}; }
|
: statement optional_comment { $$ = $1; }
|
||||||
;
|
;
|
||||||
|
|
||||||
empty_line
|
empty_line
|
||||||
: indentation optional_comment
|
: optional_comment
|
||||||
;
|
|
||||||
|
|
||||||
indentation
|
|
||||||
: indent indentation { $$ = $2 + 1ull; }
|
|
||||||
| %empty { $$ = 0ull; }
|
|
||||||
;
|
;
|
||||||
|
|
||||||
optional_comment
|
optional_comment
|
||||||
|
|
@ -251,18 +254,25 @@ statement
|
||||||
| expression left_shift_assignment expression { auto lhs = std::make_shared<ast::expression>($1); $$ = ast::assignment{ lhs, std::make_shared<ast::expression>(ast::binary_operation{ ast::binary_operation_type::left_shift, lhs, std::make_unique<ast::expression>($3), @$ }), @$ }; }
|
| expression left_shift_assignment expression { auto lhs = std::make_shared<ast::expression>($1); $$ = ast::assignment{ lhs, std::make_shared<ast::expression>(ast::binary_operation{ ast::binary_operation_type::left_shift, lhs, std::make_unique<ast::expression>($3), @$ }), @$ }; }
|
||||||
| expression right_shift_assignment expression { auto lhs = std::make_shared<ast::expression>($1); $$ = ast::assignment{ lhs, std::make_shared<ast::expression>(ast::binary_operation{ ast::binary_operation_type::right_shift, lhs, std::make_unique<ast::expression>($3), @$ }), @$ }; }
|
| expression right_shift_assignment expression { auto lhs = std::make_shared<ast::expression>($1); $$ = ast::assignment{ lhs, std::make_shared<ast::expression>(ast::binary_operation{ ast::binary_operation_type::right_shift, lhs, std::make_unique<ast::expression>($3), @$ }), @$ }; }
|
||||||
| variable_declaration { $$ = $1; }
|
| variable_declaration { $$ = $1; }
|
||||||
| if expression colon { $$ = ast::if_block{std::make_unique<ast::expression>($2), @$}; }
|
| if_chain { $$ = $1; }
|
||||||
| else colon { $$ = ast::else_block{@$}; }
|
| while expression statement_block { $$ = ast::while_block{std::make_unique<ast::expression>($2), $3, @$, @$}; }
|
||||||
| else if expression colon { $$ = ast::else_if_block{std::make_unique<ast::expression>($3), @$}; }
|
|
||||||
| while expression colon { $$ = ast::while_block{std::make_unique<ast::expression>($2), {}, @$, @$}; }
|
|
||||||
| break { $$ = ast::break_statement{@$}; }
|
| break { $$ = ast::break_statement{@$}; }
|
||||||
| continue { $$ = ast::continue_statement{@$}; }
|
| continue { $$ = ast::continue_statement{@$}; }
|
||||||
| func name lparen function_declaration_argument_list rparen function_return_type colon { $$ = ast::function_definition{{$2, $4, $6, @$}, {}}; }
|
| func name lparen function_declaration_argument_list rparen function_return_type statement_block { $$ = ast::function_definition{{$2, $4, $6, @$}, $7}; }
|
||||||
| foreign func name lparen function_declaration_argument_list rparen function_return_type { $$ = ast::foreign_function_declaration{{$3, $5, $7, @$}}; }
|
| foreign func name lparen function_declaration_argument_list rparen function_return_type { $$ = ast::foreign_function_declaration{{$3, $5, $7, @$}}; }
|
||||||
| return expression { $$ = ast::return_statement{std::make_unique<ast::expression>($2), @$}; }
|
| return expression { $$ = ast::return_statement{std::make_unique<ast::expression>($2), @$}; }
|
||||||
| return { $$ = ast::return_statement{nullptr, @$}; }
|
| return { $$ = ast::return_statement{nullptr, @$}; }
|
||||||
| struct name colon { $$ = ast::struct_definition{$2, {}, @$, @$}; }
|
| struct name lbrace field_definition_list rbrace { $$ = ast::struct_definition{$2, $4, merge(@1, @2), @$}; }
|
||||||
| name colon type_expression { $$ = ast::field_definition{$1, std::make_unique<ast::type>($3), @$}; }
|
;
|
||||||
|
|
||||||
|
if_chain
|
||||||
|
: single_if { $$ = ast::if_chain{{$1}, @$}; }
|
||||||
|
| if_chain else single_if { auto tmp = $1; tmp.blocks.push_back($3); tmp.location = @$; $$ = std::move(tmp); }
|
||||||
|
| if_chain else statement_block { auto tmp = $1; tmp.blocks.push_back({nullptr, $3, @2, merge(@2, @3)}); tmp.location = @$; $$ = std::move(tmp); }
|
||||||
|
;
|
||||||
|
|
||||||
|
single_if
|
||||||
|
: if expression statement_block { $$ = ast::if_chain::block{std::make_unique<ast::expression>($2), $3, merge(@1, @2), @$}; }
|
||||||
;
|
;
|
||||||
|
|
||||||
function_declaration_argument_list
|
function_declaration_argument_list
|
||||||
|
|
@ -301,6 +311,17 @@ variable_keyword
|
||||||
| mut { $$ = ast::value_category::_mutable; }
|
| mut { $$ = ast::value_category::_mutable; }
|
||||||
;
|
;
|
||||||
|
|
||||||
|
field_definition_list
|
||||||
|
: field_definition { std::vector<ast::field_definition> tmp; tmp.push_back(std::move($1)); $$ = std::move(tmp); }
|
||||||
|
| empty_line { $$ = {}; }
|
||||||
|
| field_definition_list newline field_definition { auto tmp = $1; tmp.push_back(std::move($3)); $$ = std::move(tmp); }
|
||||||
|
| field_definition_list newline empty_line { $$ = $1; }
|
||||||
|
;
|
||||||
|
|
||||||
|
field_definition
|
||||||
|
: name colon type_expression { $$ = ast::field_definition{$1, std::make_unique<ast::type>($3), @$}; }
|
||||||
|
;
|
||||||
|
|
||||||
type_expression
|
type_expression
|
||||||
: unit { $$ = types::unit_type{}; }
|
: unit { $$ = types::unit_type{}; }
|
||||||
| primitive_type { $$ = ast::type($1); }
|
| primitive_type { $$ = ast::type($1); }
|
||||||
|
|
|
||||||
|
|
@ -1,4 +1,4 @@
|
||||||
#include <pslang/parser/indented_statement.hpp>
|
#include <pslang/parser/finalize.hpp>
|
||||||
#include <pslang/parser/error.hpp>
|
#include <pslang/parser/error.hpp>
|
||||||
#include <pslang/ast/statement.hpp>
|
#include <pslang/ast/statement.hpp>
|
||||||
#include <pslang/ast/statement_visitor.hpp>
|
#include <pslang/ast/statement_visitor.hpp>
|
||||||
|
|
@ -11,265 +11,50 @@ namespace pslang::parser
|
||||||
namespace
|
namespace
|
||||||
{
|
{
|
||||||
|
|
||||||
struct fill_location_visitor
|
void validate(ast::statement_list_ptr statements, ast::function_definition * in_function, bool in_loop)
|
||||||
: ast::statement_visitor<fill_location_visitor>
|
|
||||||
{
|
{
|
||||||
using statement_visitor::apply;
|
for (auto & statement : statements->statements)
|
||||||
|
|
||||||
ast::location apply(ast::expression_ptr const & node)
|
|
||||||
{
|
{
|
||||||
return ast::get_location(*node);
|
if (auto if_chain = std::get_if<ast::if_chain>(statement.get()))
|
||||||
|
{
|
||||||
|
for (auto const & block : if_chain->blocks)
|
||||||
|
{
|
||||||
|
validate(block.statements, in_function, in_loop);
|
||||||
}
|
}
|
||||||
|
|
||||||
ast::location apply(ast::assignment const & node)
|
|
||||||
{
|
|
||||||
return node.location;
|
|
||||||
}
|
}
|
||||||
|
else if (auto while_block = std::get_if<ast::while_block>(statement.get()))
|
||||||
ast::location apply(ast::variable_declaration const & node)
|
|
||||||
{
|
{
|
||||||
return node.location;
|
validate(while_block->statements, in_function, true);
|
||||||
}
|
}
|
||||||
|
else if (auto function_definition = std::get_if<ast::function_definition>(statement.get()))
|
||||||
ast::location apply(ast::if_chain & node)
|
|
||||||
{
|
{
|
||||||
bool first = true;
|
validate(function_definition->statements, function_definition, in_loop);
|
||||||
for (auto & block : node.blocks)
|
|
||||||
{
|
|
||||||
block.location = apply(*block.statements);
|
|
||||||
if (first)
|
|
||||||
node.location = block.location;
|
|
||||||
else
|
|
||||||
node.location = ast::merge(node.location, block.location);
|
|
||||||
first = false;
|
|
||||||
}
|
}
|
||||||
return node.location;
|
else if (auto return_statement = std::get_if<ast::return_statement>(statement.get()))
|
||||||
}
|
|
||||||
|
|
||||||
ast::location apply(ast::while_block & node)
|
|
||||||
{
|
{
|
||||||
return node.location = ast::merge(node.prelude_location, apply(*node.statements));
|
if (!in_function)
|
||||||
}
|
|
||||||
|
|
||||||
ast::location apply(ast::break_statement & node)
|
|
||||||
{
|
|
||||||
return node.location;
|
|
||||||
}
|
|
||||||
|
|
||||||
ast::location apply(ast::continue_statement & node)
|
|
||||||
{
|
|
||||||
return node.location;
|
|
||||||
}
|
|
||||||
|
|
||||||
ast::location apply(ast::function_definition & node)
|
|
||||||
{
|
|
||||||
return node.location = ast::merge(node.prelude_location, apply(*node.statements));
|
|
||||||
}
|
|
||||||
|
|
||||||
ast::location apply(ast::foreign_function_declaration & node)
|
|
||||||
{
|
|
||||||
return node.location = node.prelude_location;
|
|
||||||
}
|
|
||||||
|
|
||||||
ast::location apply(ast::return_statement const & node)
|
|
||||||
{
|
|
||||||
return node.location;
|
|
||||||
}
|
|
||||||
|
|
||||||
ast::location apply(ast::struct_definition & node)
|
|
||||||
{
|
|
||||||
node.location = node.prelude_location;
|
|
||||||
for (auto const & field : node.fields)
|
|
||||||
node.location = ast::merge(node.location, field.location);
|
|
||||||
return node.location;
|
|
||||||
}
|
|
||||||
|
|
||||||
ast::location apply(ast::statement_list & list)
|
|
||||||
{
|
|
||||||
ast::location result;
|
|
||||||
bool first = true;
|
|
||||||
for (auto & statement : list.statements)
|
|
||||||
{
|
|
||||||
auto statement_location = apply(*statement);
|
|
||||||
if (first)
|
|
||||||
result = statement_location;
|
|
||||||
else
|
|
||||||
result = ast::merge(result, statement_location);
|
|
||||||
first = false;
|
|
||||||
}
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
ast::statement_list_ptr finalize(indented_statement_list statements)
|
|
||||||
{
|
|
||||||
ast::statement_list_ptr result = std::make_unique<ast::statement_list>();
|
|
||||||
|
|
||||||
using stack_entry = std::variant<ast::statement_list *, ast::struct_definition *>;
|
|
||||||
|
|
||||||
std::vector<stack_entry> stack;
|
|
||||||
stack.push_back(result.get());
|
|
||||||
std::size_t current_indent = 0;
|
|
||||||
std::vector<ast::function_definition *> function_stack;
|
|
||||||
std::vector<ast::statement_list *> loop_stack;
|
|
||||||
|
|
||||||
auto current_statement_list = [&](ast::location const & location) -> ast::statement_list *
|
|
||||||
{
|
|
||||||
if (stack.empty())
|
|
||||||
throw internal_error("Empty finilization stack");
|
|
||||||
|
|
||||||
if (auto list = std::get_if<ast::statement_list *>(&stack.back()))
|
|
||||||
return *list;
|
|
||||||
|
|
||||||
throw parse_error("Unexpected statement inside struct definition", location);
|
|
||||||
};
|
|
||||||
|
|
||||||
auto current_struct_definition = [&](ast::location const & location) -> ast::struct_definition *
|
|
||||||
{
|
|
||||||
if (stack.empty())
|
|
||||||
throw internal_error("Empty finilization stack");
|
|
||||||
|
|
||||||
if (auto list = std::get_if<ast::struct_definition *>(&stack.back()))
|
|
||||||
return *list;
|
|
||||||
|
|
||||||
throw parse_error("Unexpected statement outside struct definition", location);
|
|
||||||
};
|
|
||||||
|
|
||||||
for (auto & statement : statements.statements)
|
|
||||||
{
|
|
||||||
auto location = ast::get_location(*statement.statement);
|
|
||||||
|
|
||||||
if (statement.indentation > current_indent)
|
|
||||||
throw parse_error("Unexpected indent", location);
|
|
||||||
|
|
||||||
while (statement.indentation < current_indent)
|
|
||||||
{
|
|
||||||
if (stack.empty())
|
|
||||||
throw ast::invalid_ast_error("Unexpected empty indent stack", ast::get_location(*statement.statement));
|
|
||||||
if (!function_stack.empty() && std::holds_alternative<ast::statement_list *>(stack.back()) && function_stack.back()->statements.get() == std::get<ast::statement_list *>(stack.back()))
|
|
||||||
function_stack.pop_back();
|
|
||||||
if (!loop_stack.empty() && std::holds_alternative<ast::statement_list *>(stack.back()) && loop_stack.back() == std::get<ast::statement_list *>(stack.back()))
|
|
||||||
loop_stack.pop_back();
|
|
||||||
stack.pop_back();
|
|
||||||
--current_indent;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Now statement.indentation == current_indent
|
|
||||||
|
|
||||||
ast::statement_list * list = nullptr;
|
|
||||||
|
|
||||||
if (auto if_block = std::get_if<ast::if_block>(statement.statement.get()))
|
|
||||||
{
|
|
||||||
ast::if_chain chain;
|
|
||||||
chain.location = if_block->location;
|
|
||||||
chain.blocks.push_back({.condition = std::move(if_block->condition), .statements = std::make_unique<ast::statement_list>(), .prelude_location = if_block->location});
|
|
||||||
list = chain.blocks.back().statements.get();
|
|
||||||
current_statement_list(location)->statements.push_back(std::make_unique<ast::statement>(std::move(chain)));
|
|
||||||
}
|
|
||||||
else if (auto else_block = std::get_if<ast::else_block>(statement.statement.get()))
|
|
||||||
{
|
|
||||||
if (current_statement_list(location)->statements.empty())
|
|
||||||
throw parse_error("Unexpected else block", location);
|
|
||||||
auto chain = std::get_if<ast::if_chain>(current_statement_list(location)->statements.back().get());
|
|
||||||
if (!chain || chain->blocks.empty() || !chain->blocks.back().condition)
|
|
||||||
throw parse_error("Unexpected else block", location);
|
|
||||||
|
|
||||||
chain->blocks.push_back({.condition = nullptr, .statements = std::make_unique<ast::statement_list>(), .prelude_location = else_block->location});
|
|
||||||
list = chain->blocks.back().statements.get();
|
|
||||||
}
|
|
||||||
else if (auto else_if_block = std::get_if<ast::else_if_block>(statement.statement.get()))
|
|
||||||
{
|
|
||||||
if (current_statement_list(location)->statements.empty())
|
|
||||||
throw parse_error("Unexpected else if block", location);
|
|
||||||
auto chain = std::get_if<ast::if_chain>(current_statement_list(location)->statements.back().get());
|
|
||||||
if (!chain || chain->blocks.empty() || !chain->blocks.back().condition)
|
|
||||||
throw parse_error("Unexpected else if block", location);
|
|
||||||
|
|
||||||
chain->blocks.push_back({.condition = std::move(else_if_block->condition), .statements = std::make_unique<ast::statement_list>(), .prelude_location = else_if_block->location});
|
|
||||||
list = chain->blocks.back().statements.get();
|
|
||||||
}
|
|
||||||
else if (auto while_block = std::get_if<ast::while_block>(statement.statement.get()))
|
|
||||||
{
|
|
||||||
while_block->statements = std::make_unique<ast::statement_list>();
|
|
||||||
list = while_block->statements.get();
|
|
||||||
current_statement_list(location)->statements.push_back(std::make_unique<ast::statement>(std::move(*while_block)));
|
|
||||||
loop_stack.push_back(list);
|
|
||||||
}
|
|
||||||
else if (auto function_definition = std::get_if<ast::function_definition>(statement.statement.get()))
|
|
||||||
{
|
|
||||||
function_definition->statements = std::make_unique<ast::statement_list>();
|
|
||||||
auto statement = std::make_unique<ast::statement>(std::move(*function_definition));
|
|
||||||
auto function_definition_ptr = std::get_if<ast::function_definition>(statement.get());
|
|
||||||
current_statement_list(location)->statements.push_back(std::move(statement));
|
|
||||||
list = function_definition_ptr->statements.get();
|
|
||||||
function_stack.push_back(function_definition_ptr);
|
|
||||||
}
|
|
||||||
else if (auto field_definition = std::get_if<ast::field_definition>(statement.statement.get()))
|
|
||||||
{
|
|
||||||
auto current = current_struct_definition(location);
|
|
||||||
for (auto const & field : current->fields)
|
|
||||||
if (field.name == field_definition->name)
|
|
||||||
throw parse_error("Duplicate field definition: \"" + field.name + "\"", field.location);
|
|
||||||
current->fields.push_back(*field_definition);
|
|
||||||
}
|
|
||||||
else if (auto struct_definition = std::get_if<ast::struct_definition>(statement.statement.get()))
|
|
||||||
{
|
|
||||||
current_statement_list(location)->statements.push_back(std::make_unique<ast::statement>(std::move(*struct_definition)));
|
|
||||||
stack.push_back(std::get_if<ast::struct_definition>(current_statement_list(location)->statements.back().get()));
|
|
||||||
++current_indent;
|
|
||||||
}
|
|
||||||
else if (auto return_statement = std::get_if<ast::return_statement>(statement.statement.get()))
|
|
||||||
{
|
|
||||||
if (function_stack.empty())
|
|
||||||
throw parse_error("Return statement outside of function scope", return_statement->location);
|
throw parse_error("Return statement outside of function scope", return_statement->location);
|
||||||
return_statement->node = function_stack.back();
|
return_statement->node = in_function;
|
||||||
current_statement_list(location)->statements.push_back(std::make_unique<ast::statement>(std::move(*return_statement)));
|
|
||||||
}
|
}
|
||||||
else if (auto expression_ptr = std::get_if<ast::expression_ptr>(statement.statement.get()))
|
else if (auto break_statement = std::get_if<ast::break_statement>(statement.get()))
|
||||||
{
|
{
|
||||||
current_statement_list(location)->statements.push_back(std::make_unique<ast::statement>(std::move(*expression_ptr)));
|
if (!in_loop)
|
||||||
}
|
|
||||||
else if (auto assignment = std::get_if<ast::assignment>(statement.statement.get()))
|
|
||||||
{
|
|
||||||
current_statement_list(location)->statements.push_back(std::make_unique<ast::statement>(std::move(*assignment)));
|
|
||||||
}
|
|
||||||
else if (auto variable_declaration = std::get_if<ast::variable_declaration>(statement.statement.get()))
|
|
||||||
{
|
|
||||||
current_statement_list(location)->statements.push_back(std::make_unique<ast::statement>(std::move(*variable_declaration)));
|
|
||||||
}
|
|
||||||
else if (auto foreign_function_declaration = std::get_if<ast::foreign_function_declaration>(statement.statement.get()))
|
|
||||||
{
|
|
||||||
current_statement_list(location)->statements.push_back(std::make_unique<ast::statement>(std::move(*foreign_function_declaration)));
|
|
||||||
}
|
|
||||||
else if (auto break_statement = std::get_if<ast::break_statement>(statement.statement.get()))
|
|
||||||
{
|
|
||||||
if (loop_stack.empty())
|
|
||||||
throw parse_error("Break without an enclosing loop", break_statement->location);
|
throw parse_error("Break without an enclosing loop", break_statement->location);
|
||||||
current_statement_list(location)->statements.push_back(std::make_unique<ast::statement>(std::move(*break_statement)));
|
|
||||||
}
|
}
|
||||||
else if (auto continue_statement = std::get_if<ast::continue_statement>(statement.statement.get()))
|
else if (auto continue_statement = std::get_if<ast::continue_statement>(statement.get()))
|
||||||
{
|
{
|
||||||
if (loop_stack.empty())
|
if (!in_loop)
|
||||||
throw parse_error("Continue without an enclosing loop", continue_statement->location);
|
throw parse_error("Continue without an enclosing loop", continue_statement->location);
|
||||||
current_statement_list(location)->statements.push_back(std::make_unique<ast::statement>(std::move(*continue_statement)));
|
|
||||||
}
|
}
|
||||||
else
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
ast::statement_list_ptr finalize(ast::statement_list_ptr statements)
|
||||||
{
|
{
|
||||||
throw ast::invalid_ast_error(std::format("Unknown pre-statement \"{}\"", std::visit([](auto const & statement){ return typeid(statement).name(); }, *statement.statement)), location);
|
validate(statements, nullptr, false);
|
||||||
}
|
return statements;
|
||||||
|
|
||||||
if (list)
|
|
||||||
{
|
|
||||||
stack.push_back(list);
|
|
||||||
++current_indent;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fill_location_visitor{}.apply(*result);
|
|
||||||
|
|
||||||
return result;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,6 @@
|
||||||
#include <pslang/parser/parser.hpp>
|
#include <pslang/parser/parser.hpp>
|
||||||
#include <pslang/parser/context.hpp>
|
#include <pslang/parser/context.hpp>
|
||||||
#include <pslang/parser/indented_statement.hpp>
|
#include <pslang/parser/finalize.hpp>
|
||||||
#include <pslang/ast/location.hpp>
|
#include <pslang/ast/location.hpp>
|
||||||
#include "gen_parser.hpp"
|
#include "gen_parser.hpp"
|
||||||
#include "gen_lexer.hpp"
|
#include "gen_lexer.hpp"
|
||||||
|
|
@ -15,7 +15,7 @@ namespace pslang::parser
|
||||||
throw std::system_error(std::make_error_code(static_cast<std::errc>(errno)));
|
throw std::system_error(std::make_error_code(static_cast<std::errc>(errno)));
|
||||||
|
|
||||||
ast::location location{.begin = {.filename = path}, .end = {.filename = path}};
|
ast::location location{.begin = {.filename = path}, .end = {.filename = path}};
|
||||||
indented_statement_list statements;
|
ast::statement_list_ptr statements;
|
||||||
context ctx{location, statements};
|
context ctx{location, statements};
|
||||||
|
|
||||||
bison::parser parser(ctx);
|
bison::parser parser(ctx);
|
||||||
|
|
|
||||||
71
spec.txt
71
spec.txt
|
|
@ -151,20 +151,24 @@ Special built-ins:
|
||||||
======== FLOW CONTROL ========
|
======== FLOW CONTROL ========
|
||||||
|
|
||||||
Conditionals:
|
Conditionals:
|
||||||
if condition:
|
if condition {
|
||||||
statements
|
statements
|
||||||
else if condition:
|
} else if condition {
|
||||||
statements
|
statements
|
||||||
else:
|
} else {
|
||||||
statements
|
statements
|
||||||
|
}
|
||||||
|
|
||||||
While loop:
|
While loop:
|
||||||
while condition:
|
while condition {
|
||||||
statements
|
statements
|
||||||
if x:
|
if x {
|
||||||
break
|
break
|
||||||
if y:
|
}
|
||||||
|
if y {
|
||||||
continue
|
continue
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
Iterator interface:
|
Iterator interface:
|
||||||
get(it) returns the currently pointed-to value
|
get(it) returns the currently pointed-to value
|
||||||
|
|
@ -178,33 +182,37 @@ Range interface:
|
||||||
For loop:
|
For loop:
|
||||||
Operates only on ranges.
|
Operates only on ranges.
|
||||||
|
|
||||||
for x in range(10):
|
for x in range(10) {
|
||||||
do_something(x)
|
do_something(x)
|
||||||
|
}
|
||||||
|
|
||||||
i is immutable within the loop body.
|
i is immutable within the loop body.
|
||||||
|
|
||||||
Modifiable ranges use special syntax for pointers to elements:
|
Modifiable ranges use special syntax for pointers to elements:
|
||||||
|
|
||||||
for &x in array:
|
for &x in array {
|
||||||
*x += 1
|
*x += 1
|
||||||
|
}
|
||||||
|
|
||||||
The loop is equivalent to
|
The loop is equivalent to
|
||||||
|
|
||||||
mut begin = begin(range)
|
mut it = begin(range)
|
||||||
let end = end(range)
|
let end = end(range)
|
||||||
while begin != end:
|
while it != end {
|
||||||
let x = get(begin) // or get_ref(x) for pointer loop
|
let x = get(it) // or get_ref(x) for pointer loop
|
||||||
statements
|
statements
|
||||||
begin = next(begin)
|
it = next(it)
|
||||||
|
}
|
||||||
|
|
||||||
The prelude contains an implementation of range interface for built-in arrays.
|
The prelude contains an implementation of range interface for built-in arrays.
|
||||||
|
|
||||||
======== STRUCTS ========
|
======== STRUCTS ========
|
||||||
|
|
||||||
Struct types:
|
Struct types:
|
||||||
struct rect:
|
struct rect {
|
||||||
width: u32
|
width: u32
|
||||||
height: u32
|
height: u32
|
||||||
|
}
|
||||||
|
|
||||||
Creating a struct value:
|
Creating a struct value:
|
||||||
let x = rect(10u, 20u)
|
let x = rect(10u, 20u)
|
||||||
|
|
@ -221,20 +229,26 @@ Struct field access:
|
||||||
======== FUNCTIONS ========
|
======== FUNCTIONS ========
|
||||||
|
|
||||||
Function definition:
|
Function definition:
|
||||||
func foo(x: i32, y: i32) -> i32:
|
func foo(x: i32, y: i32) -> i32 {
|
||||||
return x * y
|
return x * y
|
||||||
|
}
|
||||||
|
|
||||||
func bar(x: f32): // deduced return type unit
|
func bar(x: f32) { // deduced return type unit
|
||||||
print(x)
|
print(x)
|
||||||
|
}
|
||||||
|
|
||||||
Function arguments are automatically immutable (as if declared with let).
|
Function arguments are immutable by default (as if declared with let) unless declared with mut:
|
||||||
|
|
||||||
|
func bar(mut x: u32) -> u32 {
|
||||||
|
x = (x + 1u)
|
||||||
|
x = x * x
|
||||||
|
return x
|
||||||
|
}
|
||||||
|
|
||||||
// External function: name taken literally as `powf`
|
// External function: name taken literally as `powf`
|
||||||
// and C calling convention assumed
|
// and C calling convention assumed
|
||||||
foreign func powf(x: f32, y: f32) -> f32 // no implementation
|
foreign func powf(x: f32, y: f32) -> f32 // no implementation
|
||||||
|
|
||||||
// TODO: mutable function arguments?
|
|
||||||
|
|
||||||
// TODO: function overloading? Probably requires selecting a specific overload using `as` operator to save to a value (but not on call site)
|
// TODO: function overloading? Probably requires selecting a specific overload using `as` operator to save to a value (but not on call site)
|
||||||
// TODO: alternative - Rust-like traits, aka parametric polymorphism?
|
// TODO: alternative - Rust-like traits, aka parametric polymorphism?
|
||||||
|
|
||||||
|
|
@ -265,12 +279,14 @@ Types are also considered to be values. The keyword `type` denotes the type of a
|
||||||
I.e. `typeof(16) == i32` and `typeof(i32) == type`. Incidentally, `typeof(type) == type` as well; there are no type kinds or etc.
|
I.e. `typeof(16) == i32` and `typeof(i32) == type`. Incidentally, `typeof(type) == type` as well; there are no type kinds or etc.
|
||||||
`type` can be used in any place where a type is required (variable types, function arguments, function return value, etc).
|
`type` can be used in any place where a type is required (variable types, function arguments, function return value, etc).
|
||||||
E.g.
|
E.g.
|
||||||
func foo(x: type) -> type:
|
func foo(x: type) -> type {
|
||||||
return x[4] // type of arrays of 4 elements of type x
|
return x[4] // type of arrays of 4 elements of type x
|
||||||
|
}
|
||||||
|
|
||||||
let y: type = u32
|
let y: type = u32
|
||||||
if foo(y) == u32[4]:
|
if foo(y) == u32[4] {
|
||||||
do_smth()
|
do_smth()
|
||||||
|
}
|
||||||
|
|
||||||
======== CONST EXPRESSIONS ========
|
======== CONST EXPRESSIONS ========
|
||||||
|
|
||||||
|
|
@ -283,12 +299,14 @@ E.g.
|
||||||
// Functions returning functions/structs
|
// Functions returning functions/structs
|
||||||
// Syntactic sugar for common cases
|
// Syntactic sugar for common cases
|
||||||
// Figure out: max(a,b) - how to deduce type parameters? How does it play with overloading?
|
// Figure out: max(a,b) - how to deduce type parameters? How does it play with overloading?
|
||||||
// func max(t: type):
|
// func max(t: type) {
|
||||||
// return func(x : t, y : t):
|
// return func(x : t, y : t) {
|
||||||
// if x > y:
|
// if x > y:
|
||||||
// return x
|
// return x
|
||||||
// else:
|
// else:
|
||||||
// return y
|
// return y
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
|
||||||
======== PRELUDE ========
|
======== PRELUDE ========
|
||||||
|
|
||||||
|
|
@ -298,9 +316,10 @@ It contains:
|
||||||
|
|
||||||
An array_view template struct:
|
An array_view template struct:
|
||||||
|
|
||||||
struct array_view<t: type>:
|
struct array_view<t: type> {
|
||||||
size: u64
|
size: u64
|
||||||
data: t*
|
data: t*
|
||||||
|
}
|
||||||
|
|
||||||
A specialization for strings:
|
A specialization for strings:
|
||||||
|
|
||||||
|
|
@ -318,9 +337,9 @@ It contains:
|
||||||
|
|
||||||
that allow iteration like
|
that allow iteration like
|
||||||
|
|
||||||
for i in range(10):
|
for i in range(10) { ... }
|
||||||
for i in range(5u, 10u):
|
for i in range(5u, 10u) { ... }
|
||||||
for i in range(1.0, 10.0, 0.5):
|
for i in range(1.0, 10.0, 0.5) { ... }
|
||||||
|
|
||||||
======== MODULES AND IMPORTS ========
|
======== MODULES AND IMPORTS ========
|
||||||
|
|
||||||
|
|
|
||||||
Loading…
Add table
Reference in a new issue