fix more syntax v2 bugs, update docs

This commit is contained in:
りき萌 2024-09-01 18:54:38 +02:00
parent bf37d7305c
commit d1a6fb364e
11 changed files with 544 additions and 528 deletions

View file

@ -4,4 +4,5 @@ version = "0.1.0"
edition = "2021"
[dependencies]
log.workspace = true
tiny-skia = { version = "0.11.4", default-features = false, features = ["no-std-float"] }

View file

@ -13,6 +13,7 @@ pub enum Opcode {
False,
True,
Number, // (float: f32)
Rgba, // (r: u8, g: u8, b: u8, a: u8)
// Duplicate existing values.
/// Push a value relative to the bottom of the current stack window.
@ -26,6 +27,9 @@ pub enum Opcode {
/// Set the value of a definition.
SetDef, // (index: u16)
// Create lists.
List, // (len: u16)
// Create literal functions.
Function, // (params: u8, then: u16), at `then`: (local_count: u8, capture_count: u8, captures: [(source: u8, index: u8); capture_count])

View file

@ -4,6 +4,7 @@ use core::{
};
use alloc::vec::Vec;
use log::info;
use crate::{
ast::{Ast, NodeId, NodeKind},
@ -98,12 +99,11 @@ pub fn compile_expr<'a>(c: &mut Compiler<'a>, src: &Source<'a>, node_id: NodeId)
// as they may also contain commas and other trivia.
NodeKind::Param => unreachable!("Param node should never be emitted"),
NodeKind::Color => unsupported(c, src, node_id, "color literals are not implemented yet"),
NodeKind::Ident => compile_ident(c, src, node_id),
NodeKind::Number => compile_number(c, src, node_id),
NodeKind::Tag => compile_tag(c, src, node_id),
NodeKind::List => unsupported(c, src, node_id, "list literals are not implemented yet"),
NodeKind::Number => compile_number(c, src, node_id),
NodeKind::Color => compile_color(c, src, node_id),
NodeKind::List => compile_list(c, src, node_id),
NodeKind::Unary => compile_unary(c, src, node_id),
NodeKind::Binary => compile_binary(c, src, node_id),
@ -200,18 +200,6 @@ fn compile_ident<'a>(c: &mut Compiler<'a>, src: &Source<'a>, node_id: NodeId) ->
Ok(())
}
fn compile_number(c: &mut Compiler, src: &Source, node_id: NodeId) -> CompileResult {
let literal = src.ast.span(node_id).slice(src.code);
let float: f32 = literal
.parse()
.expect("the parser should've gotten us a string parsable by the stdlib");
c.chunk.emit_opcode(Opcode::Number)?;
c.chunk.emit_f32(float)?;
Ok(())
}
fn compile_tag(c: &mut Compiler, src: &Source, node_id: NodeId) -> CompileResult {
let tag = src.ast.span(node_id).slice(src.code);
@ -230,6 +218,79 @@ fn compile_tag(c: &mut Compiler, src: &Source, node_id: NodeId) -> CompileResult
Ok(())
}
fn compile_number(c: &mut Compiler, src: &Source, node_id: NodeId) -> CompileResult {
let literal = src.ast.span(node_id).slice(src.code);
if let Ok(float) = literal.parse() {
c.chunk.emit_opcode(Opcode::Number)?;
c.chunk.emit_f32(float)?;
}
Ok(())
}
fn compile_color(c: &mut Compiler, src: &Source, node_id: NodeId) -> CompileResult {
let literal = src.ast.span(node_id).slice(src.code);
let hex = &literal[1..];
let bytes: [u8; 4] = u32::from_str_radix(hex, 16)
.ok()
.and_then(|num| match hex.len() {
3 => Some([
(((num & 0xF00) >> 8) * 0x11) as u8,
(((num & 0x0F0) >> 4) * 0x11) as u8,
((num & 0x00F) * 0x11) as u8,
0xFF,
]),
4 => Some([
(((num & 0xF000) >> 12) * 0x11) as u8,
(((num & 0x0F00) >> 8) * 0x11) as u8,
(((num & 0x00F0) >> 4) * 0x11) as u8,
((num & 0x000F) * 0x11) as u8,
]),
6 => Some([
((num & 0xFF0000) >> 16) as u8,
((num & 0x00FF00) >> 8) as u8,
(num & 0x0000FF) as u8,
0xFF,
]),
8 => Some([
((num & 0xFF000000) >> 24) as u8,
((num & 0x00FF0000) >> 16) as u8,
((num & 0x0000FF00) >> 8) as u8,
(num & 0x000000FF) as u8,
]),
_ => None,
})
.unwrap_or([0, 0, 0, 0]);
c.chunk.emit_opcode(Opcode::Rgba)?;
c.chunk.emit_bytes(&bytes)?;
Ok(())
}
fn compile_list<'a>(c: &mut Compiler<'a>, src: &Source<'a>, node_id: NodeId) -> CompileResult {
let mut walk = src.ast.walk(node_id);
let mut len = 0;
while let Some(expr) = walk.node() {
compile_expr(c, src, expr)?;
len += 1;
}
let len = u16::try_from(len).unwrap_or_else(|_| {
// For all practical intents and purposes, this should never happen---you'll most likely
// run into the chunk length limit first.
c.emit(Diagnostic::error(src.ast.span(node_id), "list is too long"));
0
});
c.chunk.emit_opcode(Opcode::List)?;
c.chunk.emit_u16(len)?;
Ok(())
}
fn compile_unary<'a>(c: &mut Compiler<'a>, src: &Source<'a>, node_id: NodeId) -> CompileResult {
let mut walk = src.ast.walk(node_id);
let Some(op) = walk.node() else { return Ok(()) };

View file

@ -17,16 +17,16 @@ impl<'a> Lexer<'a> {
pub fn new(lexis: Lexis, input: &'a SourceCode) -> Self {
Self {
lexis,
diagnostics: Vec::new(),
diagnostics: Vec::with_capacity(16),
input,
position: 0,
}
}
fn current(&self) -> char {
self.input[self.position as usize..]
.chars()
.next()
self.input
.get(self.position as usize..)
.and_then(|s| s.chars().next())
.unwrap_or('\0')
}
@ -140,7 +140,7 @@ fn whitespace_and_comments(l: &mut Lexer<'_>) {
let position = l.position;
l.advance();
if l.current() == '-' {
while l.current() != '\n' {
while l.current() != '\n' && l.current() != '\0' {
l.advance();
}
} else {

View file

@ -143,7 +143,8 @@ pub mod fns {
0x88 Nary "rgbaB" => rgba_b,
0x89 Nary "rgbaA" => rgba_a,
0x90 Nary "list" => list,
// NOTE: Not used right now, has been replaced with Opcode::List.
0x90 Nary "list (unused)" => list,
0xc0 Nary "toShape" => to_shape_f,
0xc1 Nary "line" => line,

View file

@ -5,11 +5,12 @@ use core::{
};
use alloc::{string::String, vec::Vec};
use log::info;
use crate::{
bytecode::{self, Defs, Opcode, CAPTURE_CAPTURE, CAPTURE_LOCAL},
system::{ChunkId, System},
value::{BytecodeLoc, Closure, FunctionName, Ref, RefId, Rgba, Value, Vec4},
value::{BytecodeLoc, Closure, FunctionName, List, Ref, RefId, Rgba, Value, Vec4},
};
pub struct VmLimits {
@ -208,6 +209,19 @@ impl Vm {
self.push(Value::Number(x))?;
}
Opcode::Rgba => {
let r = chunk.read_u8(&mut pc)?;
let g = chunk.read_u8(&mut pc)?;
let b = chunk.read_u8(&mut pc)?;
let a = chunk.read_u8(&mut pc)?;
self.push(Value::Rgba(Rgba {
r: r as f32 / 255.0,
g: g as f32 / 255.0,
b: b as f32 / 255.0,
a: a as f32 / 255.0,
}))?;
}
Opcode::Local => {
let index = chunk.read_u8(&mut pc)? as usize;
let value = self.get(bottom + index)?;
@ -246,6 +260,20 @@ impl Vm {
}
}
Opcode::List => {
let len = chunk.read_u16(&mut pc)? as usize;
let bottom = self.stack.len().checked_sub(len).ok_or_else(|| {
self.create_exception(
"corrupted bytecode (list has more elements than stack)",
)
})?;
let elements = self.stack[bottom..].to_vec();
self.stack.resize_with(bottom, || unreachable!());
self.track_array(&elements)?;
let id = self.create_ref(Ref::List(List { elements }))?;
self.push(Value::Ref(id))?;
}
Opcode::Function => {
let param_count = chunk.read_u8(&mut pc)?;
let then = chunk.read_u16(&mut pc)? as usize;