pr 14
This commit is contained in:
parent
127ec789bc
commit
b814a6c48d
93
crates/prometeu-compiler/tests/pbs_golden_tests.rs
Normal file
93
crates/prometeu-compiler/tests/pbs_golden_tests.rs
Normal file
@ -0,0 +1,93 @@
|
|||||||
|
use prometeu_compiler::compiler;
|
||||||
|
use prometeu_bytecode::pbc::parse_pbc;
|
||||||
|
use prometeu_bytecode::disasm::disasm;
|
||||||
|
use std::fs;
|
||||||
|
use tempfile::tempdir;
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_golden_bytecode_snapshot() {
|
||||||
|
let dir = tempdir().unwrap();
|
||||||
|
let project_dir = dir.path();
|
||||||
|
|
||||||
|
fs::write(
|
||||||
|
project_dir.join("prometeu.json"),
|
||||||
|
r#"{
|
||||||
|
"script_fe": "pbs",
|
||||||
|
"entry": "main.pbs"
|
||||||
|
}"#,
|
||||||
|
).unwrap();
|
||||||
|
|
||||||
|
let code = r#"
|
||||||
|
declare contract Gfx host {}
|
||||||
|
|
||||||
|
fn helper(val: int) -> int {
|
||||||
|
return val * 2;
|
||||||
|
}
|
||||||
|
|
||||||
|
fn main() {
|
||||||
|
Gfx.clear(0);
|
||||||
|
let x = 10;
|
||||||
|
if (x > 5) {
|
||||||
|
let y = helper(x);
|
||||||
|
}
|
||||||
|
|
||||||
|
let buf = alloc int;
|
||||||
|
mutate buf as b {
|
||||||
|
let current = b + 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
"#;
|
||||||
|
fs::write(project_dir.join("main.pbs"), code).unwrap();
|
||||||
|
|
||||||
|
let unit = compiler::compile(project_dir).expect("Failed to compile");
|
||||||
|
let pbc = parse_pbc(&unit.rom).expect("Failed to parse PBC");
|
||||||
|
let instrs = disasm(&pbc.rom).expect("Failed to disassemble");
|
||||||
|
|
||||||
|
let mut disasm_text = String::new();
|
||||||
|
for instr in instrs {
|
||||||
|
let operands_str = instr.operands.iter()
|
||||||
|
.map(|o| format!("{:?}", o))
|
||||||
|
.collect::<Vec<_>>()
|
||||||
|
.join(" ");
|
||||||
|
let line = if operands_str.is_empty() {
|
||||||
|
format!("{:04X} {:?}\n", instr.pc, instr.opcode)
|
||||||
|
} else {
|
||||||
|
format!("{:04X} {:?} {}\n", instr.pc, instr.opcode, operands_str.trim())
|
||||||
|
};
|
||||||
|
disasm_text.push_str(&line);
|
||||||
|
}
|
||||||
|
|
||||||
|
let expected_disasm = r#"0000 GetLocal U32(0)
|
||||||
|
0006 PushConst U32(1)
|
||||||
|
000C Mul
|
||||||
|
000E Ret
|
||||||
|
0010 PushConst U32(2)
|
||||||
|
0016 Syscall U32(4097)
|
||||||
|
001C PushConst U32(3)
|
||||||
|
0022 SetLocal U32(0)
|
||||||
|
0028 GetLocal U32(0)
|
||||||
|
002E PushConst U32(4)
|
||||||
|
0034 Gt
|
||||||
|
0036 JmpIfFalse U32(94)
|
||||||
|
003C Jmp U32(66)
|
||||||
|
0042 GetLocal U32(0)
|
||||||
|
0048 Call U32(0) U32(1)
|
||||||
|
0052 SetLocal U32(1)
|
||||||
|
0058 Jmp U32(100)
|
||||||
|
005E Jmp U32(100)
|
||||||
|
0064 Alloc
|
||||||
|
0066 SetLocal U32(1)
|
||||||
|
006C GetLocal U32(1)
|
||||||
|
0072 LoadRef U32(0)
|
||||||
|
0078 SetLocal U32(2)
|
||||||
|
007E GetLocal U32(2)
|
||||||
|
0084 PushConst U32(5)
|
||||||
|
008A Add
|
||||||
|
008C SetLocal U32(3)
|
||||||
|
0092 GetLocal U32(2)
|
||||||
|
0098 StoreRef U32(0)
|
||||||
|
009E Ret
|
||||||
|
"#;
|
||||||
|
|
||||||
|
assert_eq!(disasm_text, expected_disasm);
|
||||||
|
}
|
||||||
@ -1,281 +0,0 @@
|
|||||||
# arquivo: g/base.pbs
|
|
||||||
# services => singletons que soh possuem metodos, usados para DI
|
|
||||||
// default: vis?vel s? no arquivo
|
|
||||||
// mod X: exporta para o m?dulo (diret?rio)
|
|
||||||
// pub X: exporta para quem importar o arquivo (API p?blica do arquivo)
|
|
||||||
// quem importa o arquivo nao pode usar o mod, arquivos no mesmo diretorio nao precisam de import
|
|
||||||
pub service base
|
|
||||||
{
|
|
||||||
// fn define um funcao
|
|
||||||
fn do_something(a: long, b: int, c: float, d: char, e: string, f: bool): void
|
|
||||||
{
|
|
||||||
// do something
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
# arquivo: a/service.pbs
|
|
||||||
import { base } from "@g/base.pbs";
|
|
||||||
|
|
||||||
// service sem pub (default) => private, soh sera acessivel dentro do arquivo atual
|
|
||||||
service bla
|
|
||||||
{
|
|
||||||
fn do_something_else(): void
|
|
||||||
{
|
|
||||||
// do something else
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// mod indica que esse sera exportado para o modulo (cada diretorio eh um modulo) - no caso "@a"
|
|
||||||
mod service bla2
|
|
||||||
{
|
|
||||||
fn do_something_else_2(): void
|
|
||||||
{
|
|
||||||
// do something else 2
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
pub service obladi
|
|
||||||
{
|
|
||||||
fn do_something(a: long, b: int, c: float, d: char, e: string, f: bool): void
|
|
||||||
{
|
|
||||||
base.do_something(a,b,c,d,e,f);
|
|
||||||
bla.do_something_else();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
# arquivo: b/service.pbs
|
|
||||||
import { base } from "@g/base.pbs";
|
|
||||||
|
|
||||||
pub service oblada
|
|
||||||
{
|
|
||||||
fn do_something(a: long, b: int, c: float, d: char, e: string, f: bool): void
|
|
||||||
{
|
|
||||||
base.do_something(a,b,c,d,e,f);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#arquivo: main.pbs (root)
|
|
||||||
# import carrega aquela API: @ sempre se referencia a raiz do projeto
|
|
||||||
import { obladi as sa } from "@a/service.pbs";
|
|
||||||
import { oblada as sb } from "@b/service.pbs";
|
|
||||||
|
|
||||||
|
|
||||||
// funcoes podem ser declaradas fora de services, mas serao SEMPRE private
|
|
||||||
fn some(a: int, b: int): int // recebe a e b e retorna a soma
|
|
||||||
{
|
|
||||||
return a + b;
|
|
||||||
}
|
|
||||||
|
|
||||||
fn frame(): void
|
|
||||||
{
|
|
||||||
sa.do_something(1l,2,3.33,'4',"5",true); // chama o metodo do service de a
|
|
||||||
sb.do_something(1l,2,3.33,'4',"5",true); // chama o metodo do service de b
|
|
||||||
|
|
||||||
// tipos
|
|
||||||
// void: nao retorna nada
|
|
||||||
// int : i32
|
|
||||||
// long: i64
|
|
||||||
// float: f32
|
|
||||||
// double: f64
|
|
||||||
// char: u32 nao sei se sera muito efetivo, me lembro de C (char = unsigned int, UTF-8) precisa de 32 aqui?
|
|
||||||
// string: handle imut?vel para constant pool (e futuramente heap)
|
|
||||||
// bool: true/false (1 bit)
|
|
||||||
|
|
||||||
// nao eh possivel ter duas variaveis com o mesmo nome, isso eh soh um exemplo
|
|
||||||
// coercao implicita:
|
|
||||||
Sugest?o simples e consistente (recomendo para v0):
|
|
||||||
* Widen num?rico impl?cito permitido:
|
|
||||||
int -> long -> float -> double (se voc? quiser float->double tamb?m)
|
|
||||||
* Narrow/truncar NUNCA impl?cito (sempre cast expl?cito)
|
|
||||||
ent?o long = 1.5 exige as long
|
|
||||||
int = 1.5 exige as int
|
|
||||||
use as como cast
|
|
||||||
|
|
||||||
// comentario de linha
|
|
||||||
/* comentario de bloco */
|
|
||||||
let x: int = 1; // tipo explicito
|
|
||||||
let y = 1; // tipo implicito, com inferencia direta para tipos primitivos
|
|
||||||
|
|
||||||
// z nao existe aqui!
|
|
||||||
{ // scope
|
|
||||||
let z: int = 1;
|
|
||||||
}
|
|
||||||
// z nao existe aqui!
|
|
||||||
|
|
||||||
let resultado = soma(1,2); // chama a fn soma e associa a uma variavel soma - sem problemas
|
|
||||||
|
|
||||||
if (resultado > 10)
|
|
||||||
{
|
|
||||||
// sys.println(resultado);
|
|
||||||
}
|
|
||||||
else if (resultado > 100)
|
|
||||||
{
|
|
||||||
// sys.println(resultado);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
// sys.println(resultado);
|
|
||||||
}
|
|
||||||
|
|
||||||
for i from [0..10] // conta de 0 a 10 i default sempre int
|
|
||||||
{
|
|
||||||
}
|
|
||||||
|
|
||||||
// porem tb eh possivel
|
|
||||||
for i: long from [0L..10L]
|
|
||||||
{
|
|
||||||
}
|
|
||||||
|
|
||||||
for i from [0..10[ // conta de 0 a 9
|
|
||||||
{
|
|
||||||
}
|
|
||||||
|
|
||||||
for i from ]0..10] // conta de 1 a 10
|
|
||||||
{
|
|
||||||
}
|
|
||||||
|
|
||||||
for i from ]0..10[ // conta de 1 a 9
|
|
||||||
{
|
|
||||||
}
|
|
||||||
|
|
||||||
for i from [10..0] // conta de 10 a 0
|
|
||||||
{
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
// definicao de uma struct, x e y sao privados por default
|
|
||||||
define Vector(x: float, y: float)
|
|
||||||
[
|
|
||||||
(): (0, 0)
|
|
||||||
|
|
||||||
(a: float): (a, a)
|
|
||||||
{
|
|
||||||
normalize();
|
|
||||||
}
|
|
||||||
]
|
|
||||||
[[ // bloco estatico (opcional)
|
|
||||||
// o bloco estatico deve ser usado para definir constantes desse mesmo tipo e nao outro, por isso declaracao
|
|
||||||
// atraves de construtores
|
|
||||||
// assim podemos ter um tipo de enum com valores estaticos/constantes sem precisar de uma classe/instancia (vao para o constant pool)
|
|
||||||
ZERO: ()
|
|
||||||
ONE: (1, 1)
|
|
||||||
]]
|
|
||||||
{
|
|
||||||
// permitir x como sugar para this.x apenas dentro de m?todos de struct e apenas se n?o houver vari?vel local com mesmo nome. Caso exista, exige this.x.
|
|
||||||
// this s? ? permitido como tipo dentro do corpo de um define.
|
|
||||||
// this resolve para o tipo do define atual (Vector, Model, etc.)
|
|
||||||
// this tamb?m ? permitido como valor (this.x) dentro de m?todos.
|
|
||||||
// fora do define, this ? erro.
|
|
||||||
pub fn add(x: float, y: float): this
|
|
||||||
{
|
|
||||||
this.x += x;
|
|
||||||
this.y += y;
|
|
||||||
}
|
|
||||||
|
|
||||||
// privado nao pode ser usado fora da struct
|
|
||||||
fn normalize(): void
|
|
||||||
{
|
|
||||||
let l = sqrt(x*x + y*y);
|
|
||||||
x /= l;
|
|
||||||
y /= l;
|
|
||||||
}
|
|
||||||
|
|
||||||
// literals sao sempre stack allocated
|
|
||||||
// nesse caso aqui, como Vector nao eh alterado, ou seja, o valor de x e y nao muda
|
|
||||||
// o compilador passa a ref de v
|
|
||||||
// acesso aos campos
|
|
||||||
// private ? por tipo, n?o por inst?ncia
|
|
||||||
// Ent?o Vector pode acessar Vector.x em qualquer Vector.
|
|
||||||
pub fn dot(v: Vector): float
|
|
||||||
{
|
|
||||||
return x*v.x + y*v.y;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
define Model(c: Vector)
|
|
||||||
[
|
|
||||||
(): (Vector())
|
|
||||||
]
|
|
||||||
{
|
|
||||||
// nesse caso, por exemplo, como v vai ser alterado, Vector deve ser passado como mutavel (seus valores sao copiados)
|
|
||||||
// e o Vector de origem fica inalterado
|
|
||||||
fn sum(v: mut Vector): Vector
|
|
||||||
{
|
|
||||||
return v.add(c.x, c.y);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
# arquivo: z/contract.pbs
|
|
||||||
// SDK ... o compilador injeta as defs de gfx aqui
|
|
||||||
contract gfx // nome do contrato eh gfx
|
|
||||||
{
|
|
||||||
fn drawText(x: int, y: int, text: string, color: Color): void;
|
|
||||||
}
|
|
||||||
|
|
||||||
contract interface // nome do contrato eh interface (eh mongol mas nao sou muito criativo)
|
|
||||||
{
|
|
||||||
fn bla(x: int, y: int): void;
|
|
||||||
}
|
|
||||||
|
|
||||||
pub service bla1: interface
|
|
||||||
{
|
|
||||||
fn bla(x: int, y: int): void
|
|
||||||
{
|
|
||||||
// do something
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pub service bla2: interface
|
|
||||||
{
|
|
||||||
fn bla(x: int, y: int): void
|
|
||||||
{
|
|
||||||
// do something else
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
>>
|
|
||||||
Regra final recomendada (simples e limpa)
|
|
||||||
Existem dois namespaces globais
|
|
||||||
Tipos: define, interface, contract
|
|
||||||
Valores: fn, let, service
|
|
||||||
|
|
||||||
Regras
|
|
||||||
Dentro de um mesmo escopo:
|
|
||||||
? dois s?mbolos de valor com mesmo nome ? erro
|
|
||||||
? um valor n?o pode ter o mesmo nome de um tipo vis?vel ? erro (opcional, mas recomendado)
|
|
||||||
Shadowing entre escopos:
|
|
||||||
* permitido apenas para vari?veis
|
|
||||||
* n?o permitido para fun??es/services (para evitar confus?o)
|
|
||||||
|
|
||||||
>>
|
|
||||||
8) return v.add(c.x, c.y); com v: mut Vector
|
|
||||||
Se mut significa ?c?pia mut?vel?, ent?o add modifica v e retorna this (o mesmo v). Ok.
|
|
||||||
Mas a?:
|
|
||||||
* add precisa declarar retorno this e o compiler deve entender que this = Vector.
|
|
||||||
* this s? existe no contexto de define.
|
|
||||||
|
|
||||||
declare Struct // struct sem valores eh um service :D
|
|
||||||
{
|
|
||||||
pub fn sum(v): Struct
|
|
||||||
{
|
|
||||||
return this;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Isso eh soh sugar para o mesmo acima
|
|
||||||
pub fn sum(v): this
|
|
||||||
{
|
|
||||||
}
|
|
||||||
|
|
||||||
// OU
|
|
||||||
|
|
||||||
pub fn sum(v): me // mais uma keyword...
|
|
||||||
{
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
// para condicionais :
|
|
||||||
|
|
||||||
let x = when a == b then 1 else 2;
|
|
||||||
Loading…
x
Reference in New Issue
Block a user