From 78e726c9b02b903a7ad9ad0b5dfe7d353b8b0fa3 Mon Sep 17 00:00:00 2001 From: Riey Date: Thu, 13 Oct 2022 21:07:09 +0900 Subject: [PATCH 1/8] Parser use lasso --- crates/erars-ast/Cargo.toml | 1 + crates/erars-ast/src/ast.rs | 48 +++---- crates/erars-ast/src/event.rs | 20 +-- crates/erars-ast/src/lib.rs | 3 + crates/erars-ast/src/variable.rs | 20 ++- crates/erars-compiler/src/compiler.rs | 67 +++++---- crates/erars-compiler/src/instruction.rs | 9 +- crates/erars-compiler/src/parser.rs | 174 ++++++++++++++--------- crates/erars-compiler/src/parser/csv.rs | 12 +- crates/erars-compiler/src/parser/expr.rs | 53 +++---- crates/erars-lexer/src/lib.rs | 9 +- 11 files changed, 231 insertions(+), 185 deletions(-) diff --git a/crates/erars-ast/Cargo.toml b/crates/erars-ast/Cargo.toml index f3226982..319a2d24 100644 --- a/crates/erars-ast/Cargo.toml +++ b/crates/erars-ast/Cargo.toml @@ -16,6 +16,7 @@ serde = { version = "1.0.142", features = ["derive"] } smol_str = { version = "0.1.23", features = ["serde"] } strum = { version = "0.24.1", features = ["derive"] } anyhow = { version = "1" } +lasso = { version = "0.6.0", features = ["multi-threaded", "ahasher", "serialize"] } [dev-dependencies] k9 = "0.11.1" diff --git a/crates/erars-ast/src/ast.rs b/crates/erars-ast/src/ast.rs index 804d7f83..f654617e 100644 --- a/crates/erars-ast/src/ast.rs +++ b/crates/erars-ast/src/ast.rs @@ -2,18 +2,18 @@ use std::fmt; use bitflags::bitflags; use ordered_float::NotNan; -use serde::{Deserialize, Serialize}; +use serde::{Serialize, Deserialize}; use smol_str::SmolStr; use strum::{Display, EnumString}; use crate::{ command::BuiltinMethod, Alignment, BinaryOperator, BuiltinCommand, BuiltinVariable, EventFlags, - EventType, LocalVariable, UnaryOperator, Value, Variable, + EventType, Interner, LocalVariable, StrKey, UnaryOperator, Value, Variable, }; -#[derive(Clone, Debug, PartialEq, Eq, Serialize, Deserialize)] +#[derive(Clone, Debug, PartialEq, Eq)] pub enum Stmt { - Label(SmolStr), + Label(StrKey), SelectCase( Expr, Vec<(Vec, Vec)>, @@ -23,7 +23,7 @@ pub enum Stmt { PrintList(PrintFlags, Vec), PrintFormS(PrintFlags, Expr), PrintData(PrintFlags, Option, Vec>), - ReuseLastLine(Box), + ReuseLastLine(StrKey), Assign(Variable, Option, Expr), Sif(Expr, Box), If(Vec<(Expr, Vec)>, Vec), @@ -54,7 +54,7 @@ pub enum Stmt { Alignment(Alignment), } -#[derive(Clone, Debug, PartialEq, Eq, Serialize, Deserialize)] +#[derive(Clone, Debug, PartialEq, Eq)] pub struct StmtWithPos(pub Stmt, pub ScriptPosition); #[derive(Clone, Copy, Default, Debug, PartialEq, Eq, Serialize, Deserialize)] @@ -69,13 +69,13 @@ impl fmt::Display for ScriptPosition { } } -#[derive(Clone, Default, Debug, PartialEq, Eq, Serialize, Deserialize)] +#[derive(Clone, Default, Debug, PartialEq, Eq)] pub struct Function { pub header: FunctionHeader, pub body: Vec, } -#[derive(Clone, Default, Debug, PartialEq, Eq, Serialize, Deserialize)] +#[derive(Clone, Default, Debug, PartialEq, Eq)] pub struct FunctionHeader { pub file_path: SmolStr, pub name: SmolStr, @@ -83,7 +83,7 @@ pub struct FunctionHeader { pub infos: Vec, } -#[derive(Clone, Debug, PartialEq, Eq, Serialize, Deserialize)] +#[derive(Clone, Debug, PartialEq, Eq)] pub enum FunctionInfo { EventFlag(EventFlags), LocalSize(usize), @@ -93,14 +93,14 @@ pub enum FunctionInfo { FunctionS, } -#[derive(Clone, Debug, PartialEq, Eq, Serialize, Deserialize)] +#[derive(Clone, Debug, PartialEq, Eq)] pub enum Expr { - String(Box), + String(StrKey), Int(i64), FormText(FormText), Var(Variable), BuiltinVar(BuiltinVariable, Vec), - Method(Box, Vec), + Method(StrKey, Vec), BuiltinMethod(BuiltinMethod, Vec), UnaryopExpr(Box, UnaryOperator), /// ++/-- var ++/-- @@ -118,8 +118,8 @@ impl Expr { Self::Int(i.into()) } - pub fn str(s: impl Into>) -> Self { - Self::String(s.into()) + pub fn str(interner: &Interner, s: impl AsRef) -> Self { + Self::String(interner.get_or_intern(s)) } pub fn unary(op1: Self, op: UnaryOperator) -> Self { @@ -149,14 +149,14 @@ impl Expr { } } -#[derive(Clone, Debug, PartialEq, Eq, Serialize, Deserialize)] +#[derive(Clone, Debug, PartialEq, Eq)] pub enum SelectCaseCond { Single(Expr), To(Expr, Expr), Is(BinaryOperator, Expr), } -#[derive(Clone, PartialEq, Eq, Serialize, Deserialize)] +#[derive(Clone, PartialEq, Eq)] pub struct FormExpr { pub expr: Expr, pub padding: Option, @@ -169,14 +169,14 @@ impl fmt::Debug for FormExpr { } } -#[derive(Clone, PartialEq, Eq, Default, Serialize, Deserialize)] +#[derive(Clone, PartialEq, Eq, Default)] pub struct FormText { - pub first: String, - pub other: Vec<(FormExpr, String)>, + pub first: StrKey, + pub other: Vec<(FormExpr, StrKey)>, } impl FormText { - pub fn new(first: String) -> Self { + pub fn new(first: StrKey) -> Self { Self { first, other: Vec::new(), @@ -188,7 +188,7 @@ impl FormText { expr: Expr, padding: Option, align: Option, - text: String, + text: StrKey, ) { self.other.push(( FormExpr { @@ -203,10 +203,10 @@ impl FormText { impl fmt::Debug for FormText { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - write!(f, "{}", self.first)?; + write!(f, "{:?}", self.first)?; for (expr, text) in self.other.iter() { - write!(f, "{{{:?}}}{}", expr, text)?; + write!(f, "{{{:?}}}{:?}", expr, text)?; } Ok(()) @@ -223,7 +223,7 @@ option_set::option_set! { } } -#[derive(Copy, Clone, Debug, Eq, Hash, PartialEq, Serialize, Deserialize, EnumString, Display)] +#[derive(Copy, Clone, Debug, Eq, Hash, PartialEq, EnumString, Display)] pub enum BeginType { #[strum(to_string = "TITLE")] Title, diff --git a/crates/erars-ast/src/event.rs b/crates/erars-ast/src/event.rs index a10a66a4..b5a5830c 100644 --- a/crates/erars-ast/src/event.rs +++ b/crates/erars-ast/src/event.rs @@ -1,8 +1,7 @@ use enum_map::Enum; -use serde::{Deserialize, Serialize}; use strum::{Display, EnumString, IntoStaticStr}; -#[derive(Clone, Copy, Debug, Serialize, Deserialize, PartialEq, Eq, Hash)] +#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)] pub struct Event { pub ty: EventType, pub flags: EventFlags, @@ -38,7 +37,7 @@ impl Event { } } -#[derive(Clone, Copy, Debug, Serialize, Deserialize, PartialEq, Eq, Hash)] +#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)] pub enum EventFlags { None, Pre, @@ -46,20 +45,7 @@ pub enum EventFlags { Single, } -#[derive( - Enum, - Clone, - Copy, - Debug, - Serialize, - Deserialize, - PartialEq, - Eq, - Hash, - Display, - EnumString, - IntoStaticStr, -)] +#[derive(Enum, Clone, Copy, Debug, PartialEq, Eq, Hash, Display, EnumString, IntoStaticStr)] pub enum EventType { #[strum(to_string = "EVENTFIRST")] First, diff --git a/crates/erars-ast/src/lib.rs b/crates/erars-ast/src/lib.rs index 0b4d47f9..ae5b729f 100644 --- a/crates/erars-ast/src/lib.rs +++ b/crates/erars-ast/src/lib.rs @@ -15,6 +15,9 @@ pub use ordered_float::NotNan; pub use value::Value; pub use variable::*; +pub type StrKey = lasso::Spur; +pub type Interner = lasso::ThreadedRodeo; + pub fn var_name_alias(var: &str) -> &str { match var { "MAXBASE" | "UPBASE" | "DOWNBASE" | "LOSEBASE" => "BASE", diff --git a/crates/erars-ast/src/variable.rs b/crates/erars-ast/src/variable.rs index d3a2271c..8b905866 100644 --- a/crates/erars-ast/src/variable.rs +++ b/crates/erars-ast/src/variable.rs @@ -1,12 +1,9 @@ -use crate::{value::Value, Expr}; +use crate::{value::Value, Expr, StrKey}; use serde::{Deserialize, Serialize}; -use smol_str::SmolStr; use strum::{Display, EnumString, IntoStaticStr}; /// This variables are readonly system variables -#[derive( - Clone, Copy, Debug, PartialEq, Eq, Display, EnumString, Serialize, Deserialize, IntoStaticStr, -)] +#[derive(Clone, Copy, Debug, PartialEq, Eq, Display, EnumString, IntoStaticStr)] #[strum(serialize_all = "UPPERCASE")] pub enum BuiltinVariable { AblName, @@ -64,21 +61,20 @@ pub enum BuiltinVariable { GamebaseInfo, } -#[derive(Clone, Debug, Serialize, Deserialize, PartialEq, Eq)] +#[derive(Clone, Debug, PartialEq, Eq)] pub struct Variable { - pub var: Box, - pub func_extern: Option>, + pub var: StrKey, + pub func_extern: Option, pub args: Vec, } -#[derive(Clone, Debug, Serialize, Deserialize, PartialEq, Eq)] +#[derive(Clone, Debug, PartialEq, Eq)] pub struct LocalVariable { - pub var: SmolStr, + pub var: StrKey, pub info: VariableInfo, } -#[derive(Clone, Default, Debug, Serialize, Deserialize, PartialEq, Eq)] -#[serde(default)] +#[derive(Clone, Default, Debug, PartialEq, Eq, Serialize, Deserialize)] pub struct VariableInfo { pub is_chara: bool, pub is_str: bool, diff --git a/crates/erars-compiler/src/compiler.rs b/crates/erars-compiler/src/compiler.rs index fa81841f..aee8694c 100644 --- a/crates/erars-compiler/src/compiler.rs +++ b/crates/erars-compiler/src/compiler.rs @@ -1,22 +1,20 @@ use crate::{CompileError, CompileResult, Instruction}; use erars_ast::{ - BinaryOperator, BuiltinVariable, Expr, FormExpr, FormText, Function, FunctionHeader, - SelectCaseCond, Stmt, StmtWithPos, Variable, + BinaryOperator, BuiltinVariable, Expr, FormExpr, FormText, Function, FunctionHeader, Interner, + SelectCaseCond, Stmt, StmtWithPos, StrKey, Variable, }; use hashbrown::HashMap; -use serde::{Deserialize, Serialize}; -use smol_str::SmolStr; -#[derive(Clone, Debug, PartialEq, Eq, Serialize, Deserialize)] +#[derive(Clone, Debug, PartialEq, Eq)] pub struct CompiledFunction { pub header: FunctionHeader, - pub goto_labels: HashMap, + pub goto_labels: HashMap, pub body: Box<[Instruction]>, } pub struct Compiler { pub out: Vec, - pub goto_labels: HashMap, + pub goto_labels: HashMap, pub continue_marks: Vec>, pub break_marks: Vec>, } @@ -175,6 +173,15 @@ impl Compiler { Ok(()) } + fn push_count(&mut self) { + self.push(Instruction::LoadCountVarRef); + } + + fn store_count(&mut self) { + self.push(Instruction::LoadCountVarRef); + self.push(Instruction::StoreVar); + } + fn store_var(&mut self, var: Variable) -> CompileResult<()> { self.push_var_ref(var)?; self.push(Instruction::StoreVar); @@ -207,7 +214,7 @@ impl Compiler { self.push_expr(padding)?; self.push(Instruction::PadStr(align.unwrap_or_default())); } - self.push(Instruction::LoadStr(text.into_boxed_str())); + self.push(Instruction::LoadStr(text)); } self.push(Instruction::ConcatString(count)); } @@ -217,7 +224,7 @@ impl Compiler { fn push_for( &mut self, - var: Variable, + var: Option, init: Expr, end: Expr, step: Expr, @@ -236,8 +243,26 @@ impl Compiler { // goto LOOP; // } + macro_rules! push_count_var { + () => { + match var.clone() { + Some(var) => self.push_var(var)?, + None => self.push_count(), + } + }; + } + + macro_rules! store_count_var { + () => { + match var.clone() { + Some(var) => self.store_var(var)?, + None => self.store_count(), + } + }; + } + self.push_expr(init)?; - self.store_var(var.clone())?; + store_count_var!(); self.push_expr(step)?; self.push(Instruction::ReadVar); @@ -253,7 +278,7 @@ impl Compiler { // compare var with end // stack: [step, end, var] - self.push_var(var.clone())?; + push_count_var!(); // stack: [step, end, var, end] self.push(Instruction::DuplicatePrev); // stack: [step, end, exit?] @@ -270,9 +295,9 @@ impl Compiler { // add step to var self.push(Instruction::DuplicatePrev); - self.push_var(var.clone())?; + push_count_var!(); self.push(Instruction::BinaryOperator(BinaryOperator::Add)); - self.store_var(var)?; + store_count_var!(); self.push(Instruction::Goto(start)); self.insert(exit, Instruction::GotoIfNot(self.current_no())); @@ -436,17 +461,9 @@ impl Compiler { .ok_or(CompileError::BreakNotLoop)? .push(mark); } - Stmt::Repeat(end, body) => self.push_for( - Variable { - var: "COUNT".into(), - func_extern: None, - args: Vec::new(), - }, - Expr::int(0), - end, - Expr::int(1), - body, - )?, + Stmt::Repeat(end, body) => { + self.push_for(None, Expr::int(0), end, Expr::int(1), body)? + } Stmt::Do(cond, body) => { self.begin_loop_block(); let start = self.current_no(); @@ -471,7 +488,7 @@ impl Compiler { self.insert(end, Instruction::GotoIfNot(self.current_no())); self.end_loop_block(start); } - Stmt::For(var, args, body) => self.push_for(var, args.0, args.1, args.2, body)?, + Stmt::For(var, args, body) => self.push_for(Some(var), args.0, args.1, args.2, body)?, Stmt::If(else_ifs, else_part) => { let mut end_stack = Vec::with_capacity(32); diff --git a/crates/erars-compiler/src/instruction.rs b/crates/erars-compiler/src/instruction.rs index d42b1e7a..61ba9e66 100644 --- a/crates/erars-compiler/src/instruction.rs +++ b/crates/erars-compiler/src/instruction.rs @@ -1,10 +1,9 @@ use erars_ast::{ Alignment, BeginType, BinaryOperator, BuiltinCommand, BuiltinMethod, BuiltinVariable, - EventType, NotNan, PrintFlags, ScriptPosition, UnaryOperator, + EventType, NotNan, PrintFlags, ScriptPosition, StrKey, UnaryOperator, }; -use serde::{Deserialize, Serialize}; -#[derive(Clone, Debug, Eq, PartialEq, Serialize, Deserialize)] +#[derive(Clone, Copy, Debug, Eq, PartialEq)] pub enum Instruction { Nop, Pop, @@ -15,7 +14,7 @@ pub enum Instruction { /// Duplicate second value in stack DuplicatePrev, LoadInt(i64), - LoadStr(Box), + LoadStr(StrKey), EvalFormString, /// Padding first value /// @@ -23,6 +22,8 @@ pub enum Instruction { PadStr(Alignment), LoadVarRef(u32), LoadExternVarRef(u32), + /// Load COUNT + LoadCountVarRef, /// Read VarRef into Value /// /// If value is not VarRef, This is noop diff --git a/crates/erars-compiler/src/parser.rs b/crates/erars-compiler/src/parser.rs index 43834541..3c753ead 100644 --- a/crates/erars-compiler/src/parser.rs +++ b/crates/erars-compiler/src/parser.rs @@ -3,11 +3,13 @@ mod expr; use erars_ast::{ Alignment, BeginType, BinaryOperator, BuiltinCommand, EventFlags, EventType, Expr, Function, - FunctionHeader, FunctionInfo, ScriptPosition, Stmt, StmtWithPos, Variable, VariableInfo, + FunctionHeader, FunctionInfo, Interner, ScriptPosition, Stmt, StmtWithPos, StrKey, Variable, + VariableInfo, }; use erars_lexer::{ConfigToken, ErhToken, JumpType, PrintType, Token}; use hashbrown::{HashMap, HashSet}; use logos::{internal::LexerInternal, Lexer}; +use serde::{Deserialize, Serialize}; use smol_str::SmolStr; use std::{ borrow::Cow, @@ -68,7 +70,7 @@ macro_rules! try_nom { // }; // } -#[derive(Debug, Default)] +#[derive(Debug, Default, Serialize, Deserialize)] pub struct CharacterTemplate { pub no: u32, pub is_assi: bool, @@ -89,7 +91,7 @@ pub struct CharacterTemplate { pub relation: HashMap, } -#[derive(Debug)] +#[derive(Debug, Serialize, Deserialize)] pub struct ReplaceInfo { pub money_unit: String, pub unit_forward: bool, @@ -134,7 +136,7 @@ impl Default for ReplaceInfo { } } -#[derive(Clone, Debug, Default)] +#[derive(Clone, Debug, Default, Serialize, Deserialize)] pub struct Gamebase { pub code: u32, pub version: u32, @@ -147,7 +149,7 @@ pub struct Gamebase { pub title: String, } -#[derive(Clone, Debug, derivative::Derivative)] +#[derive(Clone, Debug, derivative::Derivative, Serialize, Deserialize)] #[derivative(Default)] pub struct EraConfig { pub lang: Language, @@ -201,7 +203,7 @@ impl EraConfig { } } -#[derive(Clone, Copy, Debug, EnumString, Display)] +#[derive(Clone, Copy, Debug, EnumString, Display, Serialize, Deserialize)] pub enum Language { #[strum(to_string = "JAPANESE")] Japanese, @@ -219,7 +221,7 @@ impl Default for Language { } } -#[derive(Debug)] +#[derive(Debug, Serialize, Deserialize)] pub struct DefaultLocalVarSize { pub default_local_size: Option, pub default_locals_size: Option, @@ -238,30 +240,56 @@ impl Default for DefaultLocalVarSize { } } -#[derive(Debug, Default)] +#[derive(Debug, Default, Serialize, Deserialize)] pub struct HeaderInfo { pub macros: HashMap, pub gamebase: Gamebase, pub replace: ReplaceInfo, pub character_templates: HashMap, pub item_price: HashMap, - pub var_names: HashMap>, - pub var_name_var: HashMap>, - pub global_variables: HashMap, + pub var_names: HashMap>, + pub var_name_var: HashMap>, + pub global_variables: HashMap, pub default_local_size: DefaultLocalVarSize, } impl HeaderInfo { - pub fn merge_chara_csv(&mut self, s: &str) -> ParserResult<()> { + pub fn merge_chara_csv(&mut self, interner: &Interner, s: &str) -> ParserResult<()> { let mut lex = Lexer::new(s); let mut template = CharacterTemplate::default(); + macro_rules! define_keys { + ($( + $name:ident = $str:expr; + )+) => { + $( + let $name = interner.get_or_intern_static($str); + )+ + }; + } + + define_keys! { + cstr = "CSTR"; + talent = "TALENT"; + base = "BASE"; + mark = "MARK"; + abl = "ABL"; + exp = "EXP"; + relation = "RELATION"; + equip = "EQUIP"; + cflag = "CFLAG"; + } + macro_rules! insert_template { - ($name:expr, $var:ident, $val1:expr, $val2:expr) => {{ + ($var:ident, $val1:expr, $val2:expr) => {{ let idx = match $val1.parse::() { Ok(idx) => idx, Err(_) => { - match self.var_names.get($name).and_then(|names| names.get($val1)).copied() + match self + .var_names + .get(&$var) + .and_then(|names| names.get(&interner.get_or_intern($val1))) + .copied() { Some(idx) => idx, None => error!(lex, "잘못된 숫자입니다."), @@ -276,11 +304,15 @@ impl HeaderInfo { template.$var.insert(idx, value); }}; - (@bool $name:expr, $var:ident, $val1:expr, $val2:expr) => {{ + (@bool $var:ident, $val1:expr, $val2:expr) => {{ let idx = match $val1.parse::() { Ok(idx) => idx, Err(_) => { - match self.var_names.get($name).and_then(|names| names.get($val1)).copied() + match self + .var_names + .get(&$var) + .and_then(|names| names.get(&interner.get_or_intern($val1))) + .copied() { Some(idx) => idx, None => error!(lex, "잘못된 숫자입니다."), @@ -289,11 +321,15 @@ impl HeaderInfo { }; template.$var.insert(idx, 1); }}; - (@str $name:expr, $var:ident, $val1:expr, $val2:expr) => {{ + (@str $var:ident, $val1:expr, $val2:expr) => {{ let idx = match $val1.parse::() { Ok(idx) => idx, Err(_) => { - match self.var_names.get($name).and_then(|names| names.get($val1)).copied() + match self + .var_names + .get(&$var) + .and_then(|names| names.get(&interner.get_or_intern($val1))) + .copied() { Some(idx) => idx, None => error!(lex, "잘못된 숫자입니다."), @@ -313,17 +349,17 @@ impl HeaderInfo { "あだ名" => template.nick_name = val1.into(), "助手" => template.is_assi = val1.trim() == "1", - "CSTR" => insert_template!(@str "CSTR", cstr, val1, val2), + "CSTR" => insert_template!(@str cstr, val1, val2), - "素質" => insert_template!(@bool "TALENT", talent, val1, val2), + "素質" => insert_template!(@bool talent, val1, val2), - "基礎" => insert_template!("BASE", base, val1, val2), - "刻印" => insert_template!("MARK", mark, val1, val2), - "能力" => insert_template!("ABL", abl, val1, val2), - "経験" => insert_template!("EXP", exp, val1, val2), - "相性" => insert_template!("RELATION", relation, val1, val2), - "装着物" => insert_template!("EQUIP", equip, val1, val2), - "フラグ" => insert_template!("CFLAG", cflag, val1, val2), + "基礎" => insert_template!(base, val1, val2), + "刻印" => insert_template!(mark, val1, val2), + "能力" => insert_template!(abl, val1, val2), + "経験" => insert_template!(exp, val1, val2), + "相性" => insert_template!(relation, val1, val2), + "装着物" => insert_template!(equip, val1, val2), + "フラグ" => insert_template!(cflag, val1, val2), other => log::warn!("Unknown character template name: {other}"), } } @@ -379,13 +415,13 @@ impl HeaderInfo { Ok(()) } - pub fn merge_name_csv(&mut self, var: &str, s: &str) -> ParserResult<()> { + pub fn merge_name_csv(&mut self, interner: &Interner, var: &str, s: &str) -> ParserResult<()> { let mut lex = Lexer::new(s); - let var = SmolStr::from(var); + let var = interner.get_or_intern(var); let mut name_var = BTreeMap::new(); - while let Some((n, s)) = self::csv::name_csv_line(&mut lex)? { - self.var_names.entry(var.clone()).or_default().insert(s.clone(), n); + while let Some((n, s)) = self::csv::name_csv_line(interner, &mut lex)? { + self.var_names.entry(var).or_default().insert(s, n); name_var.insert(n, s); } @@ -394,11 +430,11 @@ impl HeaderInfo { Ok(()) } - pub fn merge_item_csv(&mut self, s: &str) -> ParserResult<()> { + pub fn merge_item_csv(&mut self, interner: &Interner, s: &str) -> ParserResult<()> { let mut lex = Lexer::new(s); - let var = SmolStr::new_inline("ITEM"); + let var = interner.get_or_intern_static("ITEM"); - while let Some((n, s, price)) = self::csv::name_item_line(&mut lex)? { + while let Some((n, s, price)) = self::csv::name_item_line(&interner, &mut lex)? { self.item_price.insert(n, price); self.var_names.entry(var.clone()).or_default().insert(s.clone(), n); self.var_name_var.entry(var.clone()).or_default().insert(n, s); @@ -407,7 +443,7 @@ impl HeaderInfo { Ok(()) } - pub fn merge_variable_size_csv(&mut self, s: &str) -> ParserResult<()> { + pub fn merge_variable_size_csv(&mut self, interner: &Interner, s: &str) -> ParserResult<()> { let mut lex = Lexer::new(s); while let Some((name, sizes)) = self::csv::variable_size_line(&mut lex)? { @@ -429,8 +465,9 @@ impl HeaderInfo { sizes.and_then(|v| v.first().copied()) } name => { + let name_key = interner.get_or_intern(name); match sizes { - Some(sizes) => match self.global_variables.get_mut(name) { + Some(sizes) => match self.global_variables.get_mut(&name_key) { Some(info) => { let info_len = info.size.len(); if info.size.len() != sizes.len() { @@ -448,7 +485,7 @@ impl HeaderInfo { None => { // FORBIDDEN log::info!("Don't use {name}"); - self.global_variables.remove(name); + self.global_variables.remove(&name_key); } } } @@ -572,8 +609,9 @@ impl HeaderInfo { #[derive(Debug)] pub struct ParserContext { + pub interner: Arc, pub header: Arc, - pub local_strs: RefCell>, + pub local_strs: RefCell>, pub is_arg: Cell, pub ban_percent: Cell, pub file_path: SmolStr, @@ -582,13 +620,14 @@ pub struct ParserContext { impl Default for ParserContext { fn default() -> Self { - Self::new(Arc::default(), "".into()) + Self::new(Arc::default(), Arc::default(), "".into()) } } impl ParserContext { - pub fn new(header: Arc, file_path: SmolStr) -> Self { + pub fn new(interner: Arc, header: Arc, file_path: SmolStr) -> Self { Self { + interner, header, file_path, local_strs: RefCell::default(), @@ -627,10 +666,12 @@ impl ParserContext { } } - pub fn is_str_var(&self, ident: &str) -> bool { - if matches!(ident, "LOCALS" | "ARGS") || self.local_strs.borrow().contains(ident) { + pub fn is_str_var(&self, key: StrKey) -> bool { + if matches!(self.interner.resolve(&key), "LOCALS" | "ARGS") + || self.local_strs.borrow().contains(&key) + { true - } else if let Some(v) = self.header.global_variables.get(ident) { + } else if let Some(v) = self.header.global_variables.get(&key) { v.is_str } else { false @@ -659,7 +700,7 @@ impl ParserContext { Token::Alignment => Stmt::Alignment(take_ident!(Alignment, lex)), Token::Begin => Stmt::Begin(take_ident!(BeginType, lex)), Token::CallEvent => Stmt::CallEvent(take_ident!(EventType, lex)), - Token::LabelLine(label) => Stmt::Label(label.into()), + Token::LabelLine(label) => Stmt::Label(self.interner.get_or_intern(label)), Token::StrFormMethod((method, left)) => { let (_, form) = try_nom!(lex, self::expr::normal_form_str(self)(left)); Stmt::Method(method, vec![form]) @@ -668,15 +709,18 @@ impl ParserContext { let (_, form) = try_nom!(lex, self::expr::normal_form_str(self)(left)); Stmt::Command(com, vec![form]) } - Token::CustomDrawLine(custom) => { - Stmt::Command(BuiltinCommand::CustomDrawLine, vec![Expr::str(custom)]) - } + Token::CustomDrawLine(custom) => Stmt::Command( + BuiltinCommand::CustomDrawLine, + vec![Expr::str(&self.interner, custom)], + ), Token::Times(left) => try_nom!(lex, self::expr::times_line(self)(left)).1, Token::Throw(left) => Stmt::Command( BuiltinCommand::Throw, vec![try_nom!(lex, self::expr::normal_form_str(self)(left)).1], ), - Token::Print((flags, PrintType::Plain, form)) => Stmt::Print(flags, Expr::str(form)), + Token::Print((flags, PrintType::Plain, form)) => { + Stmt::Print(flags, Expr::str(&self.interner, form)) + } Token::Print((flags, PrintType::Data, form)) => { let form = form.trim(); let cond = if form.is_empty() { @@ -688,7 +732,7 @@ impl ParserContext { loop { match self.next_token(lex)? { - Some(Token::Data(data)) => list.push(vec![Expr::str(data)]), + Some(Token::Data(data)) => list.push(vec![Expr::str(&self.interner, data)]), Some(Token::DataForm(data)) => list.push(vec![ try_nom!(lex, self::expr::normal_form_str(self)(data)).1, ]), @@ -696,7 +740,9 @@ impl ParserContext { let mut cur_list = Vec::new(); loop { match self.next_token(lex)? { - Some(Token::Data(data)) => cur_list.push(Expr::str(data)), + Some(Token::Data(data)) => { + cur_list.push(Expr::str(&self.interner, data)) + } Some(Token::DataForm(data)) => cur_list.push( try_nom!(lex, self::expr::normal_form_str(self)(data)).1, ), @@ -931,29 +977,25 @@ impl ParserContext { Stmt::If(if_elses, block) } - Token::Inc => { - let ident = self.replace(take_ident!(lex)); - let left = cut_line(lex); - let (left, func_extern) = try_nom!(lex, self::expr::var_func_extern(left)); - let args = try_nom!(lex, self::expr::variable_arg(self, &ident)(left)).1; - let var = Variable { - var: ident.into(), - func_extern, - args, - }; - Stmt::Assign(var, Some(BinaryOperator::Add), Expr::Int(1)) - } - Token::Dec => { + tok @ (Token::Inc | Token::Dec) => { let ident = self.replace(take_ident!(lex)); let left = cut_line(lex); - let (left, func_extern) = try_nom!(lex, self::expr::var_func_extern(left)); + let (left, func_extern) = try_nom!(lex, self::expr::var_func_extern(self, left)); let args = try_nom!(lex, self::expr::variable_arg(self, &ident)(left)).1; let var = Variable { - var: ident.into(), + var: self.interner.get_or_intern(ident), func_extern, args, }; - Stmt::Assign(var, Some(BinaryOperator::Sub), Expr::Int(1)) + Stmt::Assign( + var, + Some(if tok == Token::Inc { + BinaryOperator::Add + } else { + BinaryOperator::Sub + }), + Expr::Int(1), + ) } Token::Ident(var) => { let i = cut_line(lex); diff --git a/crates/erars-compiler/src/parser/csv.rs b/crates/erars-compiler/src/parser/csv.rs index 5493ad95..2ae928a1 100644 --- a/crates/erars-compiler/src/parser/csv.rs +++ b/crates/erars-compiler/src/parser/csv.rs @@ -1,6 +1,6 @@ +use erars_ast::{Interner, StrKey}; use erars_lexer::CsvToken; use logos::Lexer; -use smol_str::SmolStr; use crate::ParserResult; @@ -24,8 +24,9 @@ pub fn csv2_line<'s>( } pub fn name_csv_line<'s>( + interner: &Interner, lex: &mut Lexer<'s, CsvToken<'s>>, -) -> ParserResult> { +) -> ParserResult> { match lex.next() { Some(CsvToken::Csv2((idx, name))) => { let idx = match idx.parse::() { @@ -33,7 +34,7 @@ pub fn name_csv_line<'s>( Err(err) => return Err((format!("숫자가 와야합니다. :{err}"), lex.span())), }; - Ok(Some((idx, name.into()))) + Ok(Some((idx, interner.get_or_intern(name)))) } Some(_) => Err((format!("CSV 형식이 잘못됐습니다."), lex.span())), None => Ok(None), @@ -52,8 +53,9 @@ pub fn chara_line<'s>( } pub fn name_item_line<'s>( + interner: &Interner, lex: &mut Lexer<'s, CsvToken<'s>>, -) -> ParserResult> { +) -> ParserResult> { match lex.next() { Some(CsvToken::Csv3((idx, name, price))) => { let idx = match idx.parse::() { @@ -65,7 +67,7 @@ pub fn name_item_line<'s>( Err(err) => return Err((format!("숫자가 와야합니다. :{err}"), lex.span())), }; - Ok(Some((idx, name.into(), price))) + Ok(Some((idx, interner.get_or_intern(name), price))) } Some(_) => Err((format!("CSV 형식이 잘못됐습니다."), lex.span())), None => Ok(None), diff --git a/crates/erars-compiler/src/parser/expr.rs b/crates/erars-compiler/src/parser/expr.rs index c44caa23..d7461640 100644 --- a/crates/erars-compiler/src/parser/expr.rs +++ b/crates/erars-compiler/src/parser/expr.rs @@ -2,7 +2,7 @@ use std::borrow::Cow; use super::ParserContext; use erars_ast::{ - Alignment, BinaryOperator, Expr, FormText, LocalVariable, NotNan, SelectCaseCond, Stmt, + Alignment, BinaryOperator, Expr, FormText, LocalVariable, NotNan, SelectCaseCond, Stmt, StrKey, UnaryOperator, Value, Variable, VariableInfo, }; use nom::{ @@ -180,7 +180,7 @@ fn form_str_cond_form<'c, 'a>( let i = i.strip_prefix("\\@").unwrap(); Ok((i, Expr::cond(cond, if_true, or_false))) } else if let Some(i) = i.strip_prefix("\\@") { - Ok((i, Expr::cond(cond, if_true, Expr::str("")))) + Ok((i, Expr::cond(cond, if_true, Expr::str(&ctx.interner, "")))) } else { unreachable!() } @@ -195,7 +195,7 @@ pub fn form_str<'c, 'a>( let normal_str = parse_form_normal_str(ty); let (mut i, (normal, mut ty)) = normal_str(i)?; - let mut form = FormText::new(normal); + let mut form = FormText::new(ctx.interner.get_or_intern(normal)); loop { let (left, expr, padding, align) = match ty { @@ -239,7 +239,7 @@ pub fn form_str<'c, 'a>( i = left; ty = next_ty; - form.push(expr, padding, align, normal.into()); + form.push(expr, padding, align, ctx.interner.get_or_intern(normal)); } Ok((i, Expr::FormText(form))) @@ -269,8 +269,10 @@ fn paran_expr<'c, 'a>(ctx: &'c ParserContext) -> impl FnMut(&'a str) -> IResult< } } -pub fn var_func_extern<'a>(i: &'a str) -> IResult<'a, Option>> { - opt(map(preceded(char('@'), ident), |s| s.into()))(i) +pub fn var_func_extern<'a>(ctx: &ParserContext, i: &'a str) -> IResult<'a, Option> { + opt(map(preceded(char('@'), ident), |s| { + ctx.interner.get_or_intern(s) + }))(i) } fn ident_or_method_expr<'c, 'a>( @@ -291,10 +293,10 @@ fn ident_or_method_expr<'c, 'a>( match ident.parse() { Ok(meth) => Ok((i, Expr::BuiltinMethod(meth, args))), - _ => Ok((i, Expr::Method(ident.into(), args))), + _ => Ok((i, Expr::Method(ctx.interner.get_or_intern(ident), args))), } } else { - let (i, func_extern) = var_func_extern(i)?; + let (i, func_extern) = var_func_extern(ctx, i)?; match ident { Cow::Borrowed(ident) => { let var = ident; @@ -307,7 +309,7 @@ fn ident_or_method_expr<'c, 'a>( Ok(( i, Expr::Var(Variable { - var: var.into(), + var: ctx.interner.get_or_intern(var), func_extern, args, }), @@ -321,7 +323,7 @@ fn ident_or_method_expr<'c, 'a>( Ok(( i, Expr::Var(Variable { - var: var.into(), + var: ctx.interner.get_or_intern(var), func_extern, args: Vec::new(), }), @@ -338,7 +340,7 @@ fn ident_or_method_expr<'c, 'a>( Ok(( i, Expr::Var(Variable { - var: m.into_boxed_str(), + var: ctx.interner.get_or_intern(m), func_extern, args, }), @@ -402,7 +404,7 @@ fn single_expr<'c, 'a>(ctx: &'c ParserContext) -> impl FnMut(&'a str) -> IResult delimited(tag("@\""), form_str(FormStrType::Str, ctx), tag("\"")), // cond form string preceded(tag("\\@"), form_str_cond_form(ctx)), - map(string, |s| Expr::String(s.into())), + map(string, |s| Expr::str(&ctx.interner, s)), map(preceded(tag("0x"), hex_digit1), |s| { Expr::Int(i64::from_str_radix(s, 16).unwrap()) }), @@ -605,7 +607,7 @@ pub fn call_jump_line<'c, 'a>( panic!("CALL/JUMP문은 식별자를 받아야합니다"); } - (i, Expr::String(function.into_owned().into_boxed_str())) + (i, Expr::str(&ctx.interner, function)) }; let (i, args) = call_arg_list(ctx)(i)?; @@ -687,11 +689,11 @@ pub fn assign_line<'c, 'a>( i = i.trim_end_matches(' '); - let (i, func_extern) = var_func_extern(i)?; + let (i, func_extern) = var_func_extern(ctx, i)?; let (i, args) = variable_arg(ctx, &var_name)(i)?; let var = Variable { - var: var_name.into(), + var: ctx.interner.get_or_intern(var_name), func_extern, args, }; @@ -708,7 +710,7 @@ pub fn assign_line<'c, 'a>( i, Stmt::Assign(var, Some(BinaryOperator::Sub), Expr::Int(1)), )) - } else if ctx.is_str_var(&var.var) { + } else if ctx.is_str_var(var.var) { let (i, op) = delimited(sp, assign_op, opt(char(' ')))(i)?; let (i, rhs) = if op.is_some() { expr(ctx)(i)? @@ -759,7 +761,7 @@ pub fn dim_line<'c, 'a>( Ok(( i, LocalVariable { - var: var.into(), + var: ctx.interner.get_or_intern(var), info, }, )) @@ -769,20 +771,18 @@ pub fn dim_line<'c, 'a>( pub fn const_eval(ctx: &ParserContext, expr: Expr) -> Result { match expr { Expr::Int(i) => Ok(Value::Int(i)), - Expr::String(s) => Ok(Value::String(s.into_string())), + Expr::String(s) => Ok(Value::String(ctx.interner.resolve(&s).into())), Expr::UnaryopExpr(expr, op) => match op { UnaryOperator::Minus => { let i = const_eval(ctx, *expr)? .into_int_err() - .map_err(Box::::from) - .map_err(Expr::String)?; + .map_err(|s| Expr::str(&ctx.interner, s))?; Ok(Value::Int(-i)) } UnaryOperator::Not => { let i = const_eval(ctx, *expr)? .into_int_err() - .map_err(Box::::from) - .map_err(Expr::String)?; + .map_err(|s| Expr::str(&ctx.interner, s))?; Ok(Value::Int(!i)) } }, @@ -850,7 +850,10 @@ fn variable_named_arg<'c, 'a>( let var = erars_ast::var_name_alias(var); let (i, ident) = ident(i)?; - if let Some(v) = ctx.header.var_names.get(var).and_then(|names| names.get(ident)) { + + let var = ctx.interner.get_or_intern(var); + let ident = ctx.interner.get_or_intern(ident); + if let Some(v) = ctx.header.var_names.get(&var).and_then(|names| names.get(&ident)) { Ok((i, Expr::int(*v))) } else { Err(nom::Err::Error(error_position!(i, ErrorKind::Verify))) @@ -885,13 +888,13 @@ pub fn variable<'c, 'a>( panic!("Variable error"); } - let (i, func_extern) = var_func_extern(i)?; + let (i, func_extern) = var_func_extern(ctx, i)?; let (i, args) = variable_arg(ctx, name)(i)?; Ok(( i, Variable { - var: name.into(), + var: ctx.interner.get_or_intern(name), func_extern, args, }, diff --git a/crates/erars-lexer/src/lib.rs b/crates/erars-lexer/src/lib.rs index be06ebc4..59c97e6e 100644 --- a/crates/erars-lexer/src/lib.rs +++ b/crates/erars-lexer/src/lib.rs @@ -34,12 +34,6 @@ pub fn parse_print_flags(mut s: &str) -> (&str, PrintFlags) { (s, flags) } -unsafe fn parse_reuse(s: &str) -> Stmt { - let s = s.get_unchecked("REUSELASTLINE".len()..); - - Stmt::ReuseLastLine(s.strip_prefix(' ').unwrap_or(s).into()) -} - unsafe fn parse_print(s: &str) -> (PrintFlags, PrintType, &str) { // skip PRINT let mut s = s.get_unchecked("PRINT".len()..); @@ -353,6 +347,8 @@ pub enum Token<'s> { Throw(&'s str), #[token("CUSTOMDRAWLINE", lex_line_left)] CustomDrawLine(&'s str), + #[regex("REUSELASTLINE", lex_line_left)] + ReuseLastLine(&'s str), #[token("RETURNFORM", |lex| normal_expr_command(lex, BuiltinCommand::Return))] #[token("PUTFORM", |lex| normal_expr_command(lex, BuiltinCommand::PutForm))] @@ -452,7 +448,6 @@ pub enum Token<'s> { #[token("CSVCFLAG", |lex| normal_expr_method(lex, BuiltinMethod::CsvCflag))] NormalExprMethod((BuiltinMethod, &'s str)), - #[regex(r"REUSELASTLINE( [^\r\n]*)?", |lex| unsafe { parse_reuse(lex.slice()) })] #[token("GETTIME", |_| single_method(BuiltinMethod::GetTime))] #[token("GETFONT", |_| single_method(BuiltinMethod::GetFont))] #[token("GETCOLOR", |_| single_method(BuiltinMethod::GetColor))] From 7c02e0cd7abdb9e560d2da18e04e695dca82b7e9 Mon Sep 17 00:00:00 2001 From: Riey Date: Thu, 13 Oct 2022 22:04:08 +0900 Subject: [PATCH 2/8] Work vm --- Cargo.lock | 57 ++++- crates/erars-ast/src/ast.rs | 6 +- crates/erars-compiler/src/compiler.rs | 2 +- crates/erars-compiler/src/parser.rs | 323 ++++++++++++++------------ crates/erars-stdio/Cargo.toml | 2 + crates/erars-stdio/src/main.rs | 55 ++++- crates/erars-vm/Cargo.toml | 1 + crates/erars-vm/src/context.rs | 6 +- crates/erars-vm/src/function.rs | 38 +-- crates/erars-vm/src/lib.rs | 2 + crates/erars-vm/src/system_func.rs | 4 +- crates/erars-vm/src/terminal_vm.rs | 4 +- crates/erars-vm/src/variable.rs | 321 +++++++++++++++---------- 13 files changed, 511 insertions(+), 310 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 3dd0e159..d9bed226 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -210,6 +210,15 @@ version = "0.5.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "3a8241f3ebb85c056b509d4327ad0358fbbba6ffb340bf388f26350aeda225b1" +[[package]] +name = "bincode" +version = "1.3.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b1f45e9417d87227c7a56d22e471c6206462cba514c7590c09aff4cf6d1ddcad" +dependencies = [ + "serde", +] + [[package]] name = "bitflags" version = "1.3.2" @@ -534,6 +543,16 @@ version = "0.2.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "5b0dd6aab3061be00b739299a1d8b10da43848f0d857b30f30ab83226680cd06" +[[package]] +name = "dashmap" +version = "4.0.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e77a43b28d0668df09411cb0bc9a8c2adc40f9a048afe863e05fd43251e8e39c" +dependencies = [ + "cfg-if", + "num_cpus", +] + [[package]] name = "derivative" version = "2.2.0" @@ -626,8 +645,9 @@ dependencies = [ "anyhow", "bitflags", "enum-map", - "hashbrown", + "hashbrown 0.12.3", "k9", + "lasso", "num-derive", "num-traits", "option_set", @@ -646,7 +666,7 @@ dependencies = [ "enum-map", "erars-ast", "erars-lexer", - "hashbrown", + "hashbrown 0.12.3", "k9", "log", "logos", @@ -697,7 +717,7 @@ dependencies = [ "bitflags", "cow-utils", "erars-ast", - "hashbrown", + "hashbrown 0.12.3", "logos", "option_set", "serde", @@ -718,7 +738,7 @@ dependencies = [ "erars-ui", "erars-vm", "glob", - "hashbrown", + "hashbrown 0.12.3", "log", "parking_lot", "rayon", @@ -732,6 +752,7 @@ version = "0.1.0" dependencies = [ "ansi_term", "anyhow", + "bincode", "clap 4.0.10", "erars-ast", "erars-compiler", @@ -741,6 +762,7 @@ dependencies = [ "flexi_logger", "log", "log-panics", + "rmp-serde", "ron", ] @@ -769,6 +791,7 @@ version = "0.1.0" dependencies = [ "anyhow", "arrayvec", + "bincode", "bitflags", "css-color", "derivative", @@ -779,7 +802,7 @@ dependencies = [ "erars-ui", "flate2", "glob", - "hashbrown", + "hashbrown 0.12.3", "itertools", "k9", "log", @@ -937,6 +960,16 @@ version = "1.8.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "eabb4a44450da02c90444cf74558da904edde8fb4e9035a9a6a4e15445af0bd7" +[[package]] +name = "hashbrown" +version = "0.11.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ab5ef0d4909ef3724cc8cce6ccc8572c5c817592e9285f5464f8e86f8bd3726e" +dependencies = [ + "ahash", + "serde", +] + [[package]] name = "hashbrown" version = "0.12.3" @@ -1065,7 +1098,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "10a35a97730320ffe8e2d410b5d3b69279b98d2c14bdb8b70ea89ecf7888d41e" dependencies = [ "autocfg", - "hashbrown", + "hashbrown 0.12.3", ] [[package]] @@ -1109,6 +1142,18 @@ dependencies = [ "term_size", ] +[[package]] +name = "lasso" +version = "0.6.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "aeb7b21a526375c5ca55f1a6dfd4e1fad9fa4edd750f530252a718a44b2608f0" +dependencies = [ + "ahash", + "dashmap", + "hashbrown 0.11.2", + "serde", +] + [[package]] name = "lazy_static" version = "1.4.0" diff --git a/crates/erars-ast/src/ast.rs b/crates/erars-ast/src/ast.rs index f654617e..60f34d96 100644 --- a/crates/erars-ast/src/ast.rs +++ b/crates/erars-ast/src/ast.rs @@ -69,16 +69,16 @@ impl fmt::Display for ScriptPosition { } } -#[derive(Clone, Default, Debug, PartialEq, Eq)] +#[derive(Clone, Debug, PartialEq, Eq)] pub struct Function { pub header: FunctionHeader, pub body: Vec, } -#[derive(Clone, Default, Debug, PartialEq, Eq)] +#[derive(Clone, Debug, PartialEq, Eq)] pub struct FunctionHeader { pub file_path: SmolStr, - pub name: SmolStr, + pub name: StrKey, pub args: Vec<(Variable, Option)>, pub infos: Vec, } diff --git a/crates/erars-compiler/src/compiler.rs b/crates/erars-compiler/src/compiler.rs index aee8694c..27a5f8d9 100644 --- a/crates/erars-compiler/src/compiler.rs +++ b/crates/erars-compiler/src/compiler.rs @@ -1,6 +1,6 @@ use crate::{CompileError, CompileResult, Instruction}; use erars_ast::{ - BinaryOperator, BuiltinVariable, Expr, FormExpr, FormText, Function, FunctionHeader, Interner, + BinaryOperator, BuiltinVariable, Expr, FormExpr, FormText, Function, FunctionHeader, SelectCaseCond, Stmt, StmtWithPos, StrKey, Variable, }; use hashbrown::HashMap; diff --git a/crates/erars-compiler/src/parser.rs b/crates/erars-compiler/src/parser.rs index 3c753ead..b69dcbb8 100644 --- a/crates/erars-compiler/src/parser.rs +++ b/crates/erars-compiler/src/parser.rs @@ -1,6 +1,7 @@ mod csv; mod expr; +use enum_map::{Enum, EnumMap}; use erars_ast::{ Alignment, BeginType, BinaryOperator, BuiltinCommand, EventFlags, EventType, Expr, Function, FunctionHeader, FunctionInfo, Interner, ScriptPosition, Stmt, StmtWithPos, StrKey, Variable, @@ -18,7 +19,7 @@ use std::{ mem, sync::Arc, }; -use strum::{Display, EnumString}; +use strum::{Display, EnumString, IntoStaticStr}; pub use crate::error::{ParserError, ParserResult}; use crate::CompiledFunction; @@ -1020,178 +1021,204 @@ impl ParserContext { lex: &mut Lexer<'s, Token<'s>>, ) -> ParserResult> { let mut out = Vec::with_capacity(1024); - let mut compiler = crate::compiler::Compiler::new(); - - let mut current_func_header = FunctionHeader::default(); loop { match self.next_token(lex)? { - Some(Token::At(left)) => { - let (label, args) = try_nom!(lex, self::expr::function_line(self)(left)).1; - if !current_func_header.name.is_empty() { - out.push(CompiledFunction { - header: mem::take(&mut current_func_header), - body: compiler.out.into_boxed_slice(), - goto_labels: compiler.goto_labels, - }); - compiler = crate::compiler::Compiler::new(); - } + Some(Token::At(mut left)) => loop { self.local_strs.borrow_mut().clear(); - current_func_header.file_path = self.file_path.clone(); - current_func_header.name = label.into(); - current_func_header.args = args; - } - Some(Token::Function) => { - current_func_header.infos.push(FunctionInfo::Function); - } - Some(Token::FunctionS) => { - current_func_header.infos.push(FunctionInfo::FunctionS); - } - Some(Token::Pri) => { - current_func_header - .infos - .push(FunctionInfo::EventFlag(EventFlags::Pre)); - } - Some(Token::Later) => { - current_func_header - .infos - .push(FunctionInfo::EventFlag(EventFlags::Later)); - } - Some(Token::Single) => { - current_func_header - .infos - .push(FunctionInfo::EventFlag(EventFlags::Single)); - } - Some(Token::Dim(left)) => { - let var = try_nom!(lex, self::expr::dim_line(self, false)(left)).1; - current_func_header.infos.push(FunctionInfo::Dim(var)); - } - Some(Token::DimS(left)) => { - let var = try_nom!(lex, self::expr::dim_line(self, true)(left)).1; - self.local_strs.borrow_mut().insert(var.var.clone()); - current_func_header.infos.push(FunctionInfo::Dim(var)); - } - Some(Token::LocalSize(size)) => { - let size = self::expr::const_eval_log_error( - self, - try_nom!(lex, self::expr::expr(self)(size)).1, - ) - .try_into_int() - .unwrap(); - current_func_header.infos.push(FunctionInfo::LocalSize(size as usize)); - } - Some(Token::LocalSSize(size)) => { - let size = self::expr::const_eval_log_error( - self, - try_nom!(lex, self::expr::expr(self)(size)).1, - ) - .try_into_int() - .unwrap(); - current_func_header - .infos - .push(FunctionInfo::LocalSSize(size as usize)); - } - Some(other) => match self.parse_stmt(other, lex) { - Ok(stmt) => match compiler.push_stmt_with_pos(stmt) { - Ok(_) => {} - Err(err) => error!(lex, err.to_string()), - }, - Err(err) => { - return Err(err); + let mut compiler = crate::compiler::Compiler::new(); + let (label, args) = try_nom!(lex, self::expr::function_line(self)(left)).1; + + let mut infos = Vec::new(); + + match self.next_token(lex)? { + Some(Token::At(new_left)) => { + left = new_left; + + out.push(CompiledFunction { + header: FunctionHeader { + name: self.interner.get_or_intern(label), + args, + file_path: self.file_path.clone(), + infos: Vec::new(), + }, + goto_labels: compiler.goto_labels, + body: compiler.out.into_boxed_slice(), + }); + + continue; + } + None => { + out.push(CompiledFunction { + header: FunctionHeader { + name: self.interner.get_or_intern(label), + args, + file_path: self.file_path.clone(), + infos: Vec::new(), + }, + goto_labels: compiler.goto_labels, + body: compiler.out.into_boxed_slice(), + }); + + break; + } + Some(Token::Function) => { + infos.push(FunctionInfo::Function); + } + Some(Token::FunctionS) => { + infos.push(FunctionInfo::FunctionS); + } + Some(Token::Pri) => { + infos.push(FunctionInfo::EventFlag(EventFlags::Pre)); + } + Some(Token::Later) => { + infos.push(FunctionInfo::EventFlag(EventFlags::Later)); + } + Some(Token::Single) => { + infos.push(FunctionInfo::EventFlag(EventFlags::Single)); + } + Some(Token::Dim(left)) => { + let var = try_nom!(lex, self::expr::dim_line(self, false)(left)).1; + infos.push(FunctionInfo::Dim(var)); + } + Some(Token::DimS(left)) => { + let var = try_nom!(lex, self::expr::dim_line(self, true)(left)).1; + self.local_strs.borrow_mut().insert(var.var.clone()); + infos.push(FunctionInfo::Dim(var)); + } + Some(Token::LocalSize(size)) => { + let size = self::expr::const_eval_log_error( + self, + try_nom!(lex, self::expr::expr(self)(size)).1, + ) + .try_into_int() + .unwrap(); + infos.push(FunctionInfo::LocalSize(size as usize)); + } + Some(Token::LocalSSize(size)) => { + let size = self::expr::const_eval_log_error( + self, + try_nom!(lex, self::expr::expr(self)(size)).1, + ) + .try_into_int() + .unwrap(); + infos.push(FunctionInfo::LocalSSize(size as usize)); + } + Some(other) => match self.parse_stmt(other, lex) { + Ok(stmt) => match compiler.push_stmt_with_pos(stmt) { + Ok(_) => {} + Err(err) => error!(lex, err.to_string()), + }, + Err(err) => { + return Err(err); + } + }, } }, + Some(_) => error!(lex, "함수는 @로 시작해야 합니다."), None => break, } } - if !current_func_header.name.is_empty() { - out.push(CompiledFunction { - header: mem::take(&mut current_func_header), - body: compiler.out.into_boxed_slice(), - goto_labels: compiler.goto_labels, - }); - } - Ok(out) } pub fn parse<'s>(&self, lex: &mut Lexer<'s, Token<'s>>) -> ParserResult> { let mut out = Vec::new(); - let mut current_func = Function::default(); loop { match self.next_token(lex)? { - Some(Token::At(left)) => { - let (label, args) = try_nom!(lex, self::expr::function_line(self)(left)).1; - if !current_func.header.name.is_empty() { - out.push(mem::take(&mut current_func)); - } + Some(Token::At(mut left)) => loop { self.local_strs.borrow_mut().clear(); - current_func.header.file_path = self.file_path.clone(); - current_func.header.name = label.into(); - current_func.header.args = args; - } - Some(Token::Function) => { - current_func.header.infos.push(FunctionInfo::Function); - } - Some(Token::FunctionS) => { - current_func.header.infos.push(FunctionInfo::FunctionS); - } - Some(Token::Pri) => { - current_func - .header - .infos - .push(FunctionInfo::EventFlag(EventFlags::Pre)); - } - Some(Token::Later) => { - current_func - .header - .infos - .push(FunctionInfo::EventFlag(EventFlags::Later)); - } - Some(Token::Single) => { - current_func - .header - .infos - .push(FunctionInfo::EventFlag(EventFlags::Single)); - } - Some(Token::Dim(left)) => { - let var = try_nom!(lex, self::expr::dim_line(self, false)(left)).1; - current_func.header.infos.push(FunctionInfo::Dim(var)); - } - Some(Token::DimS(left)) => { - let var = try_nom!(lex, self::expr::dim_line(self, true)(left)).1; - self.local_strs.borrow_mut().insert(var.var.clone()); - current_func.header.infos.push(FunctionInfo::Dim(var)); - } - Some(Token::LocalSize(size)) => { - let var = try_nom!(lex, self::expr::expr(self)(size)) - .1 - .into_const_int() - .unwrap(); - current_func.header.infos.push(FunctionInfo::LocalSize(var as usize)); - } - Some(Token::LocalSSize(size)) => { - let var = try_nom!(lex, self::expr::expr(self)(size)) - .1 - .into_const_int() - .unwrap(); - current_func.header.infos.push(FunctionInfo::LocalSSize(var as usize)); - } - Some(other) => match self.parse_stmt(other, lex) { - Ok(stmt) => current_func.body.push(stmt), - Err(err) => { - return Err(err); + let mut body = Vec::new(); + let (label, args) = try_nom!(lex, self::expr::function_line(self)(left)).1; + + let mut infos = Vec::new(); + + match self.next_token(lex)? { + Some(Token::At(new_left)) => { + left = new_left; + + out.push(Function { + header: FunctionHeader { + name: self.interner.get_or_intern(label), + args, + file_path: self.file_path.clone(), + infos: Vec::new(), + }, + body: std::mem::take(&mut body), + }); + + continue; + } + None => { + out.push(Function { + header: FunctionHeader { + name: self.interner.get_or_intern(label), + args, + file_path: self.file_path.clone(), + infos: Vec::new(), + }, + body, + }); + + break; + } + Some(Token::Function) => { + infos.push(FunctionInfo::Function); + } + Some(Token::FunctionS) => { + infos.push(FunctionInfo::FunctionS); + } + Some(Token::Pri) => { + infos.push(FunctionInfo::EventFlag(EventFlags::Pre)); + } + Some(Token::Later) => { + infos.push(FunctionInfo::EventFlag(EventFlags::Later)); + } + Some(Token::Single) => { + infos.push(FunctionInfo::EventFlag(EventFlags::Single)); + } + Some(Token::Dim(left)) => { + let var = try_nom!(lex, self::expr::dim_line(self, false)(left)).1; + infos.push(FunctionInfo::Dim(var)); + } + Some(Token::DimS(left)) => { + let var = try_nom!(lex, self::expr::dim_line(self, true)(left)).1; + self.local_strs.borrow_mut().insert(var.var.clone()); + infos.push(FunctionInfo::Dim(var)); + } + Some(Token::LocalSize(size)) => { + let size = self::expr::const_eval_log_error( + self, + try_nom!(lex, self::expr::expr(self)(size)).1, + ) + .try_into_int() + .unwrap(); + infos.push(FunctionInfo::LocalSize(size as usize)); + } + Some(Token::LocalSSize(size)) => { + let size = self::expr::const_eval_log_error( + self, + try_nom!(lex, self::expr::expr(self)(size)).1, + ) + .try_into_int() + .unwrap(); + infos.push(FunctionInfo::LocalSSize(size as usize)); + } + Some(other) => match self.parse_stmt(other, lex) { + Ok(stmt) => body.push(stmt), + Err(err) => { + return Err(err); + } + }, } }, + Some(_) => error!(lex, "함수는 @로 시작해야 합니다."), None => break, } } - if !current_func.header.name.is_empty() { - out.push(current_func); - } - Ok(out) } } diff --git a/crates/erars-stdio/Cargo.toml b/crates/erars-stdio/Cargo.toml index 1c17c63e..c095f20d 100644 --- a/crates/erars-stdio/Cargo.toml +++ b/crates/erars-stdio/Cargo.toml @@ -18,6 +18,8 @@ ron = "0.8.0" anyhow = "1.0.65" log = "0.4.17" ansi_term = "0.12.1" +rmp-serde = "1.1.1" +bincode = "1.3.3" [features] with-backtrace = ["log-panics/with-backtrace"] diff --git a/crates/erars-stdio/src/main.rs b/crates/erars-stdio/src/main.rs index b0f1ba50..a2774b20 100644 --- a/crates/erars-stdio/src/main.rs +++ b/crates/erars-stdio/src/main.rs @@ -1,7 +1,10 @@ mod stdio_frontend; +use std::{path::Path, time::Instant}; + use erars_ast::Value; use erars_loader::run_script; +use erars_vm::{ScriptSaveFormat, ScriptSaveFormatRef, TerminalVm, VmContext}; #[derive(clap::Parser)] #[clap(author, version, about)] @@ -25,11 +28,19 @@ struct Args { #[clap(long, help = "Don't print logs")] quite: bool, + + #[clap(long, help = "Save script file")] + save: bool, + + #[clap(long, help = "Load script file")] + load: bool, } fn main() { use flexi_logger::*; + let time = Instant::now(); + let args: Args = clap::Parser::parse(); let _handle = if args.quite { @@ -61,7 +72,45 @@ fn main() { None => Vec::new(), }; - let (vm, mut ctx) = run_script(args.target_path, inputs).unwrap(); - let mut frontend = stdio_frontend::StdioFrontend::new(ctx.config.printc_width); - frontend.run(&vm, &mut ctx).unwrap(); + let (vm, mut ctx) = if args.load { + let format: ScriptSaveFormat = bincode::deserialize_from(std::io::BufReader::new( + std::fs::File::open("game.era").unwrap(), + )) + .unwrap(); + + log::info!("dic: {:?}", format.dic); + + todo!(); + + ( + TerminalVm { + dic: format.dic, + sav_path: Path::new(&args.target_path).join("sav"), + }, + VmContext::new(format.header_info.into(), format.config.into()), + ) + } else { + run_script(args.target_path, inputs).unwrap() + }; + + let diff = time.elapsed(); + println!("Game load done! {}ms elapsed", diff.as_millis()); + + if args.save { + let time = Instant::now(); + bincode::serialize_into( + &mut std::io::BufWriter::new(std::fs::File::create("game.era").unwrap()), + &ScriptSaveFormatRef { + dic: &vm.dic, + config: &ctx.config, + header_info: &ctx.header_info, + }, + ) + .unwrap(); + let diff = time.elapsed(); + println!("Save done! {}ms elapsed", diff.as_millis()); + } else { + let mut frontend = stdio_frontend::StdioFrontend::new(ctx.config.printc_width); + frontend.run(&vm, &mut ctx).unwrap(); + } } diff --git a/crates/erars-vm/Cargo.toml b/crates/erars-vm/Cargo.toml index 8f824934..23fd0805 100644 --- a/crates/erars-vm/Cargo.toml +++ b/crates/erars-vm/Cargo.toml @@ -36,6 +36,7 @@ css-color = "0.2.4" regex = "1.6.0" twoway = "0.2.2" derivative = "2.2.0" +bincode = "1.3.3" [dev-dependencies] k9 = "0.11.5" diff --git a/crates/erars-vm/src/context.rs b/crates/erars-vm/src/context.rs index 04603d78..777afa1d 100644 --- a/crates/erars-vm/src/context.rs +++ b/crates/erars-vm/src/context.rs @@ -4,7 +4,7 @@ use smol_str::SmolStr; use std::fmt; use std::sync::Arc; -use erars_ast::{BeginType, EventType, ScriptPosition, Value, VariableInfo}; +use erars_ast::{BeginType, EventType, ScriptPosition, Value, VariableInfo, Interner}; use erars_compiler::{EraConfig, HeaderInfo}; use crate::{SystemState, VariableStorage, VmVariable}; @@ -40,9 +40,9 @@ pub struct VmContext { } impl VmContext { - pub fn new(header_info: Arc, config: Arc) -> Self { + pub fn new(interner: Arc, header_info: Arc, config: Arc) -> Self { let mut ret = Self { - var: VariableStorage::new(&header_info.global_variables), + var: VariableStorage::new(interner, &header_info.global_variables), header_info, state: vec![StateCallStack { state: (BeginType::Title.into()), diff --git a/crates/erars-vm/src/function.rs b/crates/erars-vm/src/function.rs index c727b50b..1b20ad65 100644 --- a/crates/erars-vm/src/function.rs +++ b/crates/erars-vm/src/function.rs @@ -1,42 +1,42 @@ use anyhow::{anyhow, Result}; use arrayvec::ArrayVec; use enum_map::EnumMap; +use erars_ast::StrKey; use erars_compiler::DefaultLocalVarSize; use hashbrown::HashMap; use smol_str::SmolStr; use erars_ast::{Event, EventFlags, EventType, Expr, FunctionInfo, Value, VariableInfo}; use erars_compiler::{CompiledFunction, Instruction}; -use serde::{Deserialize, Serialize}; use crate::VariableStorage; use crate::Workflow; -#[derive(Clone, Default, Debug, Serialize, Deserialize, PartialEq, Eq)] +#[derive(Clone, Default, Debug, PartialEq, Eq)] pub struct FunctionBody { - file_path: SmolStr, - is_function: bool, - is_functions: bool, - body: Box<[Instruction]>, - goto_labels: HashMap, - args: Vec<(Box, Option, ArrayVec)>, + pub file_path: SmolStr, + pub is_function: bool, + pub is_functions: bool, + pub goto_labels: HashMap, + pub args: Vec<(StrKey, Option, ArrayVec)>, + pub body: Box<[Instruction]>, } impl FunctionBody { pub fn push_arg( &mut self, - var: Box, + var: StrKey, default_value: Option, indices: ArrayVec, ) { self.args.push((var, default_value, indices)); } - pub fn goto_labels(&self) -> &HashMap { + pub fn goto_labels(&self) -> &HashMap { &self.goto_labels } - pub fn args(&self) -> &[(Box, Option, ArrayVec)] { + pub fn args(&self) -> &[(StrKey, Option, ArrayVec)] { &self.args } @@ -57,11 +57,11 @@ impl FunctionBody { } } -#[derive(Clone, Default, Debug, Serialize, Deserialize, PartialEq, Eq)] +#[derive(Clone, Default, Debug, PartialEq, Eq)] pub struct EventCollection { - single: Option, - events: Vec, - empty_count: usize, + pub single: Option, + pub events: Vec, + pub empty_count: usize, } impl EventCollection { @@ -87,10 +87,10 @@ impl EventCollection { } } -#[derive(Clone, Debug, Serialize, Deserialize, PartialEq, Eq)] +#[derive(Clone, Debug, PartialEq, Eq)] pub struct FunctionDic { - normal: HashMap, - event: EnumMap, + pub normal: HashMap, + pub event: EnumMap, } impl FunctionDic { @@ -158,7 +158,7 @@ impl FunctionDic { assert!(!body.is_function); } FunctionInfo::Dim(local) => { - var_dic.add_local_info(header.name.clone(), local.var, local.info); + var_dic.add_local_info(header.name, local.var, local.info); } } } diff --git a/crates/erars-vm/src/lib.rs b/crates/erars-vm/src/lib.rs index 6532f803..c35a8934 100644 --- a/crates/erars-vm/src/lib.rs +++ b/crates/erars-vm/src/lib.rs @@ -18,6 +18,8 @@ pub use crate::{ variable::{UniformVariable, VariableStorage, VmVariable}, }; +pub use erars_compiler::{EraConfig, HeaderInfo, Instruction, Language}; + #[derive(Display, Debug, Clone, PartialEq, Eq)] pub enum Workflow { Return, diff --git a/crates/erars-vm/src/system_func.rs b/crates/erars-vm/src/system_func.rs index 362c8446..545bc13b 100644 --- a/crates/erars-vm/src/system_func.rs +++ b/crates/erars-vm/src/system_func.rs @@ -438,7 +438,9 @@ fn load_savs(vm: &TerminalVm, ctx: &mut VmContext) -> HashMap { @@ -37,58 +41,70 @@ pub struct SerializableVariableStorage { pub version: u32, character_len: usize, rand_seed: [u8; 32], - variables: HashMap, - local_variables: HashMap)>>, + variables: HashMap, + local_variables: HashMap)>>, } #[derive(Serialize, Deserialize, Clone, Debug)] pub struct SerializableGlobalVariableStorage { pub code: u32, pub version: u32, - variables: HashMap, - local_variables: HashMap)>>, + variables: HashMap, + local_variables: HashMap)>>, } #[derive(Clone)] pub struct VariableStorage { + interner: Arc, character_len: usize, rng: ChaCha20Rng, - variables: HashMap, - local_variables: HashMap)>>, + variables: HashMap, + local_variables: HashMap)>>, + known_variables: EnumMap, } impl VariableStorage { - pub fn new(infos: &HashMap) -> Self { + pub fn new(interner: Arc, infos: &HashMap) -> Self { let mut variables = HashMap::new(); for (k, v) in infos { - variables.insert(k.clone(), (v.clone(), UniformVariable::new(v))); + variables.insert( + *k, + (v.clone(), UniformVariable::new(v)), + ); } Self { + interner, character_len: 0, rng: ChaCha20Rng::from_entropy(), variables, local_variables: HashMap::new(), + known_variables: enum_map::enum_map! { + v => interner.get_or_intern_static(<&str>::from(v)), + }, } } + #[inline] + pub fn known_key(&self, var: KnownVariableNames) -> StrKey { + self.known_variables[var] + } + fn load_variables( &mut self, - variables: HashMap, - local_variables: HashMap< - SmolStr, - HashMap)>, - >, + variables: HashMap, + local_variables: HashMap)>>, ) { for (k, (info, var)) in variables { - let (now_info, now_var) = match self.variables.get_mut(&k) { - Some(v) => v, - _ => { - log::warn!("Ignore non existing variable {k}"); - continue; - } - }; + let (now_info, now_var) = + match self.interner.get(k).and_then(|k| self.variables.get_mut(&k)) { + Some(v) => v, + _ => { + log::warn!("Ignore non existing variable {k}"); + continue; + } + }; if info != *now_info { log::warn!("Info mismatched! Ignore load variable {k}"); @@ -99,7 +115,11 @@ impl VariableStorage { } for (func_name, vars) in local_variables { - let now_local_var = match self.local_variables.get_mut(&func_name) { + let now_local_var = match self + .interner + .get(&func_name) + .and_then(|k| self.local_variables.get_mut(&k)) + { Some(v) => v, None => { log::warn!("Ignore non existing function {func_name}"); @@ -108,13 +128,14 @@ impl VariableStorage { }; for (k, (info, var)) in vars { - let (now_info, now_var) = match now_local_var.get_mut(&k) { - Some(v) => v, - _ => { - log::warn!("Ignore non existing variable {func_name}@{k}"); - continue; - } - }; + let (now_info, now_var) = + match self.interner.get(&k).and_then(|k| now_local_var.get_mut(&k)) { + Some(v) => v, + _ => { + log::warn!("Ignore non existing variable {func_name}@{k}"); + continue; + } + }; if info != *now_info { log::warn!("Info mismatched! Ignore load variable {k}"); @@ -151,35 +172,65 @@ impl VariableStorage { Ok(()) } - pub fn get_serializable( + fn extract_var( &self, - header: &HeaderInfo, - description: String, - ) -> SerializableVariableStorage { + is_global: bool, + ) -> ( + HashMap, + HashMap>, + ) { let variables = self .variables - .iter() + .par_iter() .filter_map(|(name, (info, var))| { - if info.is_savedata && !info.is_global { - Some((name.clone(), (info.clone(), var.clone()))) + if info.is_savedata && info.is_global == is_global { + Some(( + self.interner.resolve(name).to_string(), + (info.clone(), var.clone()), + )) } else { None } }) .collect(); - let mut local_variables = HashMap::<_, HashMap<_, _>>::new(); + let local_variables = self + .local_variables + .par_iter() + .filter_map(|(fn_name, vars)| { + let vars: HashMap<_, _> = vars + .iter() + .filter_map(|(name, (info, var))| { + if info.is_savedata && info.is_global == is_global { + Some(( + self.interner.resolve(name).to_string(), + (info.clone(), var.clone()), + )) + } else { + None + } + }) + .collect(); + + if vars.is_empty() { + None + } else { + let fn_name: String = self.interner.resolve(fn_name).into(); - for (fn_name, vars) in self.local_variables.iter() { - for (name, (info, var)) in vars.iter() { - if info.is_savedata && !info.is_global { - local_variables - .entry(fn_name.clone()) - .or_default() - .insert(name.clone(), (info.clone(), var.clone())); + Some((fn_name, vars)) } - } - } + }) + .collect(); + + (variables, local_variables) + } + + pub fn get_serializable( + &self, + header: &HeaderInfo, + description: String, + ) -> SerializableVariableStorage { + let (variables, local_variables) = self.extract_var(false); SerializableVariableStorage { code: header.gamebase.code, @@ -196,30 +247,7 @@ impl VariableStorage { &self, header: &HeaderInfo, ) -> SerializableGlobalVariableStorage { - let variables = self - .variables - .iter() - .filter_map(|(name, (info, var))| { - if info.is_savedata && info.is_global { - Some((name.clone(), (info.clone(), var.clone()))) - } else { - None - } - }) - .collect(); - - let mut local_variables = HashMap::<_, HashMap<_, _>>::new(); - - for (fn_name, vars) in self.local_variables.iter() { - for (name, (info, var)) in vars.iter() { - if var.is_some() && info.is_savedata && info.is_global { - local_variables - .entry(fn_name.clone()) - .or_default() - .insert(name.clone(), (info.clone(), var.clone())); - } - } - } + let (variables, local_variables) = self.extract_var(true); SerializableGlobalVariableStorage { code: header.gamebase.code, @@ -235,7 +263,7 @@ impl VariableStorage { fn upcheck_internal( tx: &mut VirtualConsole, - palam_name: &BTreeMap, + palam_name: &BTreeMap, palam: &mut [i64], up: &mut [i64], down: &mut [i64], @@ -275,7 +303,7 @@ impl VariableStorage { &mut self, tx: &mut VirtualConsole, idx: usize, - palam_name: &BTreeMap, + palam_name: &BTreeMap, ) -> Result<()> { let (palam, up, down) = self.get_var3("PALAM", "UP", "DOWN")?; @@ -290,7 +318,7 @@ impl VariableStorage { &mut self, tx: &mut VirtualConsole, idx: usize, - palam_name: &BTreeMap, + palam_name: &BTreeMap, ) -> Result<()> { let (palam, up, down) = self.get_var3("PALAM", "CUP", "CDOWN")?; @@ -337,34 +365,34 @@ impl VariableStorage { pub fn set_result(&mut self, i: i64) { log::debug!("set result {i}"); - *self.ref_int("RESULT", &[]).unwrap() = i; + *self.ref_int(KnownVariableNames::Result, &[]).unwrap() = i; } pub fn set_results(&mut self, s: String) { log::debug!("set results {s}"); - *self.ref_str("RESULTS", &[]).unwrap() = s; + *self.ref_str(KnownVariableNames::ResultS, &[]).unwrap() = s; } pub fn character_len(&self) -> usize { self.character_len } - pub fn add_local_info(&mut self, func: SmolStr, var_name: SmolStr, info: VariableInfo) { + pub fn add_local_info(&mut self, func: StrKey, var_name: StrKey, info: VariableInfo) { self.local_variables .entry(func) .or_default() .insert(var_name, (info, None)); } - pub fn ref_int(&mut self, name: &str, args: &[usize]) -> Result<&mut i64> { + pub fn ref_int(&mut self, name: impl StrKeyLike, args: &[usize]) -> Result<&mut i64> { let (_, var, idx) = self.index_var(name, args)?; Ok(&mut var.as_int()?[idx]) } pub fn ref_local_int( &mut self, - func_name: &str, - name: &str, + func_name: impl StrKeyLike, + name: impl StrKeyLike, args: &[usize], ) -> Result<&mut i64> { let (_, var, idx) = self.index_local_var(func_name, name, args)?; @@ -373,8 +401,8 @@ impl VariableStorage { pub fn ref_maybe_local_int( &mut self, - func_name: &str, - name: &str, + func_name: impl StrKeyLike, + name: impl StrKeyLike, args: &[usize], ) -> Result<&mut i64> { if self.is_local_var(func_name, name) { @@ -384,15 +412,15 @@ impl VariableStorage { } } - pub fn ref_str(&mut self, name: &str, args: &[usize]) -> Result<&mut String> { + pub fn ref_str(&mut self, name: impl StrKeyLike, args: &[usize]) -> Result<&mut String> { let (_, var, idx) = self.index_var(name, args)?; Ok(&mut var.as_str()?[idx]) } pub fn ref_local_str( &mut self, - func_name: &str, - name: &str, + func_name: impl StrKeyLike, + name: impl StrKeyLike, args: &[usize], ) -> Result<&mut String> { let (_, var, idx) = self.index_local_var(func_name, name, args)?; @@ -401,8 +429,8 @@ impl VariableStorage { pub fn ref_maybe_local_str( &mut self, - func_name: &str, - name: &str, + func_name: impl StrKeyLike, + name: impl StrKeyLike, args: &[usize], ) -> Result<&mut String> { if self.is_local_var(func_name, name) { @@ -412,20 +440,20 @@ impl VariableStorage { } } - pub fn read_int(&mut self, name: &str, args: &[usize]) -> Result { + pub fn read_int(&mut self, name: impl StrKeyLike, args: &[usize]) -> Result { let (_, var, idx) = self.index_var(name, args)?; Ok(var.as_int()?[idx]) } - pub fn read_local_int(&mut self, func_name: &str, name: &str, args: &[usize]) -> Result { + pub fn read_local_int(&mut self, func_name: impl StrKeyLike, name: impl StrKeyLike, args: &[usize]) -> Result { let (_, var, idx) = self.index_local_var(func_name, name, args)?; Ok(var.as_int()?[idx]) } pub fn read_maybe_local_int( &mut self, - func_name: &str, - name: &str, + func_name: impl StrKeyLike, + name: impl StrKeyLike, args: &[usize], ) -> Result { if self.is_local_var(func_name, name) { @@ -435,17 +463,19 @@ impl VariableStorage { } } - pub fn read_str(&mut self, name: &str, args: &[usize]) -> Result { + pub fn read_str(&mut self, name: impl StrKeyLike, args: &[usize]) -> Result { let (_, var, idx) = self.index_var(name, args)?; Ok(var.as_str()?[idx].clone()) } pub fn index_var( &mut self, - name: &str, + name: impl StrKeyLike, args: &[usize], ) -> Result<(&mut VariableInfo, &mut VmVariable, usize)> { - let target = if name != "TARGET" { + let name = name.get_key(self); + + let target = if name != self.known_key(KnownVariableNames::Target) { self.read_int("TARGET", &[])? } else { // NEED for break recursion @@ -460,7 +490,7 @@ impl VariableStorage { UniformVariable::Character(cvar) => { let c_idx = c_idx.unwrap_or_else(|| target as usize); cvar.get_mut(c_idx) - .ok_or_else(|| anyhow!("Variable {name} Character index {c_idx} not exists"))? + .ok_or_else(|| anyhow!("Variable {name:?} Character index {c_idx} not exists"))? } UniformVariable::Normal(var) => var, }; @@ -470,8 +500,8 @@ impl VariableStorage { pub fn index_local_var( &mut self, - func_name: &str, - name: &str, + func_name: impl StrKeyLike, + name: impl StrKeyLike, args: &[usize], ) -> Result<(&mut VariableInfo, &mut VmVariable, usize)> { let target = self.read_int("TARGET", &[])?; @@ -495,8 +525,8 @@ impl VariableStorage { pub fn index_maybe_local_var( &mut self, - func_name: &str, - name: &str, + func_name: impl StrKeyLike, + name: impl StrKeyLike, args: &[usize], ) -> Result<(&mut VariableInfo, &mut VmVariable, usize)> { if self.is_local_var(func_name, name) { @@ -508,15 +538,15 @@ impl VariableStorage { pub fn get_local_var( &mut self, - func_name: &str, - var: &str, + func_name: impl StrKeyLike, + var: impl StrKeyLike, ) -> Result<(&mut VariableInfo, &mut UniformVariable)> { let (info, var) = self .local_variables - .get_mut(func_name) + .get_mut(&func_name.get_key(self)) .unwrap() - .get_mut(var) - .ok_or_else(|| anyhow!("Variable {} is not exists", var))?; + .get_mut(&var.get_key(self)) + .ok_or_else(|| anyhow!("Variable {:?} is not exists", var))?; if var.is_none() { let mut var_ = UniformVariable::new(info); @@ -532,17 +562,17 @@ impl VariableStorage { Ok((info, var.as_mut().unwrap())) } - pub fn is_local_var(&self, func: &str, var: &str) -> bool { - match self.local_variables.get(func) { - Some(v) => v.contains_key(var), + pub fn is_local_var(&self, func: impl StrKeyLike, var: impl StrKeyLike) -> bool { + match self.local_variables.get(&func.get_key(self)) { + Some(v) => v.contains_key(&var.get_key(self)), None => false, } } pub fn get_maybe_local_var( &mut self, - func: &str, - var: &str, + func: impl StrKeyLike, + var: impl StrKeyLike, ) -> Result<(&mut VariableInfo, &mut UniformVariable)> { if self.is_local_var(func, var) { self.get_local_var(func, var) @@ -551,8 +581,8 @@ impl VariableStorage { } } - pub fn reset_var(&mut self, var: &str) -> Result<()> { - let (info, var) = self.get_var(var)?; + pub fn reset_var(&mut self, var: impl StrKeyLike) -> Result<()> { + let (info, var) = self.get_var(&var.get_key(self))?; if info.is_str { match var { @@ -573,45 +603,45 @@ impl VariableStorage { Ok(()) } - pub fn get_var(&mut self, var: &str) -> Result<(&mut VariableInfo, &mut UniformVariable)> { + pub fn get_var(&mut self, var: impl StrKeyLike) -> Result<(&mut VariableInfo, &mut UniformVariable)> { let (l, r) = self .variables - .get_mut(var) - .ok_or_else(|| anyhow!("Variable {} is not exists", var))?; + .get_mut(&var.get_key(self)) + .ok_or_else(|| anyhow!("Variable {var:?} is not exists"))?; Ok((l, r)) } pub fn get_var2( &mut self, - l: &str, - r: &str, + v1: impl StrKeyLike, + v2: impl StrKeyLike, ) -> Result<( (&mut VariableInfo, &mut UniformVariable), (&mut VariableInfo, &mut UniformVariable), )> { - match self.variables.get_many_mut([l, r]) { + match self.variables.get_many_mut([&v1.get_key(self), &v2.get_key(self)]) { Some([(ll, lr), (rl, rr)]) => Ok(((ll, lr), (rl, rr))), None => { - bail!("Variable {l} or {r} is not exists"); + bail!("Variable {v1:?} or {v2:?} is not exists"); } } } pub fn get_var3( &mut self, - v1: &str, - v2: &str, - v3: &str, + v1: impl StrKeyLike, + v2: impl StrKeyLike, + v3: impl StrKeyLike, ) -> Result<( (&mut VariableInfo, &mut UniformVariable), (&mut VariableInfo, &mut UniformVariable), (&mut VariableInfo, &mut UniformVariable), )> { - match self.variables.get_many_mut([v1, v2, v3]) { + match self.variables.get_many_mut([&v1.get_key(self), &v2.get_key(self), &v3.get_key(self)]) { Some([(l1, r1), (l2, r2), (l3, r3)]) => Ok(((l1, r1), (l2, r2), (l3, r3))), None => { - bail!("Variable {v1} or {v2} or {v3} is not exists"); + bail!("Variable {v1:?} or {v2:?} or {v3:?} is not exists"); } } } @@ -874,3 +904,46 @@ impl UniformVariable { } } } + +#[derive(Debug, Clone, Copy, PartialEq, Eq, Enum, IntoStaticStr, Display)] +#[strum(serialize_all = "UPPERCASE")] +pub enum KnownVariableNames { + Count, + NextCom, + PrevCom, + CurrentCom, + Target, + Local, + LocalS, + Arg, + ArgS, + Result, + ResultS, + Palam, + PalamLv, + Exp, + ExpLv, + Up, + Down, + Cup, + Cdown, +} + +trait StrKeyLike: Debug + Copy { + fn get_key(self, var: &VariableStorage) -> StrKey; +} + +impl StrKeyLike for StrKey { + #[inline(always)] + fn get_key(self, _: &VariableStorage) -> StrKey { + self + } +} + +impl StrKeyLike for KnownVariableNames { + #[inline(always)] + fn get_key(self, var: &VariableStorage) -> StrKey { + var.known_key(self) + } +} + From 6a6fecaae39db9d89db09738583677aea06a7840 Mon Sep 17 00:00:00 2001 From: Riey Date: Fri, 14 Oct 2022 10:46:52 +0900 Subject: [PATCH 3/8] Convert vm --- crates/erars-vm/src/context.rs | 74 +++++--- crates/erars-vm/src/function.rs | 36 ++-- crates/erars-vm/src/system_func.rs | 17 +- crates/erars-vm/src/terminal_vm.rs | 38 ++-- crates/erars-vm/src/terminal_vm/executor.rs | 78 ++++---- crates/erars-vm/src/variable.rs | 195 +++++++++++++++----- 6 files changed, 295 insertions(+), 143 deletions(-) diff --git a/crates/erars-vm/src/context.rs b/crates/erars-vm/src/context.rs index 777afa1d..da44a02e 100644 --- a/crates/erars-vm/src/context.rs +++ b/crates/erars-vm/src/context.rs @@ -4,9 +4,10 @@ use smol_str::SmolStr; use std::fmt; use std::sync::Arc; -use erars_ast::{BeginType, EventType, ScriptPosition, Value, VariableInfo, Interner}; +use erars_ast::{BeginType, EventType, Interner, ScriptPosition, StrKey, Value, VariableInfo}; use erars_compiler::{EraConfig, HeaderInfo}; +use crate::variable::StrKeyLike; use crate::{SystemState, VariableStorage, VmVariable}; use super::UniformVariable; @@ -40,7 +41,11 @@ pub struct VmContext { } impl VmContext { - pub fn new(interner: Arc, header_info: Arc, config: Arc) -> Self { + pub fn new( + interner: Arc, + header_info: Arc, + config: Arc, + ) -> Self { let mut ret = Self { var: VariableStorage::new(interner, &header_info.global_variables), header_info, @@ -112,6 +117,7 @@ impl VmContext { pub fn reduce_local_value(&mut self, value: LocalValue) -> Result { match value { LocalValue::Value(v) => Ok(v), + LocalValue::InternedStr(s) => Ok(self.var.resolve_key(s).into()), LocalValue::VarRef(r) => self.read_var_ref(&r), } } @@ -128,7 +134,7 @@ impl VmContext { var.as_int()? .get_mut(idx) - .ok_or_else(|| anyhow::anyhow!("Variable {} out of index", var_ref.name)) + .ok_or_else(|| anyhow::anyhow!("Variable {:?} out of index", var_ref.name)) } pub fn set_var_ref(&mut self, var_ref: &VariableRef, value: Value) -> Result<()> { @@ -141,7 +147,7 @@ impl VmContext { &'c mut self, r: &VariableRef, ) -> Result<(&'c mut VariableInfo, &'c mut VmVariable, usize)> { - self.var.index_maybe_local_var(&r.func_name, &r.name, &r.idxs) + self.var.index_maybe_local_var(r.func_name, r.name, &r.idxs) } pub fn resolve_var_ref_raw<'c>( @@ -152,7 +158,7 @@ impl VmContext { &'c mut UniformVariable, ArrayVec, )> { - let (info, var) = self.var.get_maybe_local_var(&r.func_name, &r.name)?; + let (info, var) = self.var.get_maybe_local_var(r.func_name, r.name)?; Ok((info, var, r.idxs.clone())) } @@ -238,7 +244,7 @@ impl VmContext { pub fn take_arg_list( &mut self, - var_name: Option<&str>, + var_name: Option, count: u32, ) -> Result> { self.take_value_list(count)? @@ -246,9 +252,13 @@ impl VmContext { .map(|value| match value { Value::Int(i) => usize::try_from(i).map_err(anyhow::Error::from), Value::String(str) => match var_name + .map(|s| self.var.resolve_key(s)) .map(erars_ast::var_name_alias) - .and_then(|var_name| self.header_info.var_names.get(var_name)) - .and_then(|names| names.get(str.as_str())) + .map(|s| self.var.interner().get_or_intern(s)) + .and_then(|var_name| { + self.header_info.var_names.get(&var_name.get_key(&self.var)) + }) + .and_then(|names| names.get(&str.get_key(&self.var))) { Some(value) => Ok(*value as usize), None => anyhow::bail!("Can't index variable with String"), @@ -264,10 +274,12 @@ impl VmContext { match arg { LocalValue::Value(v) => ret.push(v), LocalValue::VarRef(var) => { - let var = - self.var.index_maybe_local_var(&var.func_name, &var.name, &var.idxs)?; + let var = self.var.index_maybe_local_var(var.func_name, var.name, &var.idxs)?; ret.push(var.1.get(var.2)?); } + LocalValue::InternedStr(s) => { + ret.push(self.var.resolve_key(s).into()); + } } } @@ -288,7 +300,7 @@ impl VmContext { self.stack.push(prev); } - pub fn push_var_ref(&mut self, name: String, func_name: String, idxs: ArrayVec) { + pub fn push_var_ref(&mut self, name: StrKey, func_name: StrKey, idxs: ArrayVec) { let var_ref = VariableRef { func_name, name, @@ -297,6 +309,10 @@ impl VmContext { self.stack.push(LocalValue::VarRef(var_ref)); } + pub fn push_strkey(&mut self, key: StrKey) { + self.stack.push(LocalValue::InternedStr(key)); + } + pub fn push(&mut self, value: impl Into) { self.stack.push(LocalValue::Value(value.into())); } @@ -319,6 +335,7 @@ impl VmContext { match self.pop()? { LocalValue::Value(v) => Ok(v), LocalValue::VarRef(var_ref) => self.read_var_ref(&var_ref), + LocalValue::InternedStr(s) => Ok(Value::String(self.var.resolve_key(s).into())), } } @@ -330,26 +347,30 @@ impl VmContext { self.pop_value().and_then(|v| v.try_into_str()) } + pub fn pop_strkey(&mut self) -> Result { + let value = match self.pop()? { + LocalValue::InternedStr(s) => return Ok(s), + LocalValue::Value(v) => v, + LocalValue::VarRef(var_ref) => self.read_var_ref(&var_ref)?, + }; + + match value { + Value::Int(_) => bail!("Value is not Str"), + Value::String(s) => Ok(self.var.interner().get_or_intern(s)), + } + } + pub fn pop_int(&mut self) -> Result { self.pop_value().and_then(|v| v.try_into_int()) } } -#[derive(Debug, Clone)] +#[derive(Debug, Clone, Copy)] pub enum FunctionIdentifier { - Normal(SmolStr), + Normal(StrKey), Event(EventType, usize), } -impl FunctionIdentifier { - pub fn name(&self) -> &str { - match self { - Self::Normal(s) => s, - Self::Event(ty, _) => ty.into(), - } - } -} - #[derive(Debug, Clone)] pub struct Callstack { pub func_name: FunctionIdentifier, @@ -361,14 +382,14 @@ pub struct Callstack { #[derive(Clone)] pub struct VariableRef { - pub name: String, - pub func_name: String, + pub name: StrKey, + pub func_name: StrKey, pub idxs: ArrayVec, } impl fmt::Debug for VariableRef { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - write!(f, "{}@{}", self.name, self.func_name)?; + write!(f, "{:?}@{:?}", self.name, self.func_name)?; for idx in self.idxs.iter() { write!(f, ":{}", idx)?; @@ -380,7 +401,7 @@ impl fmt::Debug for VariableRef { impl fmt::Display for VariableRef { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - write!(f, "{}", self.name)?; + write!(f, "{:?}", self.name)?; for idx in self.idxs.iter() { write!(f, ":{}", idx)?; @@ -393,6 +414,7 @@ impl fmt::Display for VariableRef { #[derive(Clone, Debug)] pub enum LocalValue { Value(Value), + InternedStr(StrKey), VarRef(VariableRef), } diff --git a/crates/erars-vm/src/function.rs b/crates/erars-vm/src/function.rs index 1b20ad65..080fcf0a 100644 --- a/crates/erars-vm/src/function.rs +++ b/crates/erars-vm/src/function.rs @@ -1,6 +1,9 @@ +use std::sync::Arc; + use anyhow::{anyhow, Result}; use arrayvec::ArrayVec; use enum_map::EnumMap; +use erars_ast::Interner; use erars_ast::StrKey; use erars_compiler::DefaultLocalVarSize; use hashbrown::HashMap; @@ -9,6 +12,7 @@ use smol_str::SmolStr; use erars_ast::{Event, EventFlags, EventType, Expr, FunctionInfo, Value, VariableInfo}; use erars_compiler::{CompiledFunction, Instruction}; +use crate::variable::KnownVariableNames; use crate::VariableStorage; use crate::Workflow; @@ -89,13 +93,15 @@ impl EventCollection { #[derive(Clone, Debug, PartialEq, Eq)] pub struct FunctionDic { + pub interner: Arc, pub normal: HashMap, pub event: EnumMap, } impl FunctionDic { - pub fn new() -> Self { + pub fn new(interner: Arc) -> Self { Self { + interner, normal: HashMap::new(), event: EnumMap::default(), } @@ -165,15 +171,15 @@ impl FunctionDic { // builtin locals - static LOCAL: SmolStr = SmolStr::new_inline("LOCAL"); - static LOCALS: SmolStr = SmolStr::new_inline("LOCALS"); - static ARG: SmolStr = SmolStr::new_inline("ARG"); - static ARGS: SmolStr = SmolStr::new_inline("ARGS"); + let local = var_dic.known_key(KnownVariableNames::Local); + let locals = var_dic.known_key(KnownVariableNames::LocalS); + let arg = var_dic.known_key(KnownVariableNames::Arg); + let args = var_dic.known_key(KnownVariableNames::ArgS); if let Some(local_size) = local_size { var_dic.add_local_info( header.name.clone(), - LOCAL.clone(), + local, VariableInfo { size: vec![local_size], ..Default::default() @@ -184,7 +190,7 @@ impl FunctionDic { if let Some(locals_size) = locals_size { var_dic.add_local_info( header.name.clone(), - LOCALS.clone(), + locals, VariableInfo { is_str: true, size: vec![locals_size], @@ -196,7 +202,7 @@ impl FunctionDic { if let Some(arg_size) = default_var_size.default_arg_size { var_dic.add_local_info( header.name.clone(), - ARG.clone(), + arg, VariableInfo { size: vec![arg_size], ..Default::default() @@ -207,7 +213,7 @@ impl FunctionDic { if let Some(args_size) = default_var_size.default_args_size { var_dic.add_local_info( header.name.clone(), - ARGS.clone(), + args, VariableInfo { is_str: true, size: vec![args_size], @@ -216,14 +222,14 @@ impl FunctionDic { ); } - if let Ok(ty) = header.name.parse::() { + if let Ok(ty) = self.interner.resolve(&header.name).parse::() { self.insert_event(Event { ty, flags }, body); } else { self.insert_func(header.name, body); } } - pub fn insert_func(&mut self, name: SmolStr, body: FunctionBody) { + pub fn insert_func(&mut self, name: StrKey, body: FunctionBody) { self.normal.insert(name, body); } @@ -248,12 +254,12 @@ impl FunctionDic { &self.event[ty] } - pub fn get_func_opt(&self, name: &str) -> Option<&FunctionBody> { - self.normal.get(name) + pub fn get_func_opt(&self, name: StrKey) -> Option<&FunctionBody> { + self.normal.get(&name) } - pub fn get_func(&self, name: &str) -> Result<&FunctionBody> { + pub fn get_func(&self, name: StrKey) -> Result<&FunctionBody> { self.get_func_opt(name) - .ok_or_else(|| anyhow!("Function {} is not exists", name)) + .ok_or_else(|| anyhow!("Function {} is not exists", self.interner.resolve(&name))) } } diff --git a/crates/erars-vm/src/system_func.rs b/crates/erars-vm/src/system_func.rs index 545bc13b..2a301506 100644 --- a/crates/erars-vm/src/system_func.rs +++ b/crates/erars-vm/src/system_func.rs @@ -1,3 +1,4 @@ +use crate::variable::KnownVariableNames::*; use anyhow::{bail, Result}; use erars_ast::{BeginType, EventType}; use erars_ui::{InputRequest, InputRequestType, VirtualConsole}; @@ -180,7 +181,7 @@ impl SystemState { ctx.var.reset_train_data()?; call_event!(vm, EventType::Train, tx, ctx) } - 1 => match ctx.var.read_int("NEXTCOM", &[])? { + 1 => match ctx.var.read_int(NextCom, &[])? { no if no >= 0 => { *com_no = no as u32; *phase = 10; @@ -191,8 +192,9 @@ impl SystemState { } }, 2 => { + let train = ctx.var.interner().get_or_intern("TRAIN"); for (no, _) in - ctx.header_info.clone().var_name_var["TRAIN"].range(*com_able_no..) + ctx.header_info.clone().var_name_var[&train].range(*com_able_no..) { *com_able_no = *no; match vm.try_call(&format!("COM_ABLE{no}"), &[], tx, ctx)? { @@ -214,8 +216,9 @@ impl SystemState { return Ok(call!(vm, "SHOW_USERCOM", tx, ctx)); } 3 => { + let train = ctx.var.interner().get_or_intern("TRAIN"); let no = *com_able_no; - let name = &ctx.header_info.var_name_var["TRAIN"][&no]; + let name = &ctx.header_info.var_name_var[&train][&no]; if ctx.var.get_result() != 0 || ctx.header_info.replace.comable_init != 0 { if ctx.config.printc_count != 0 && *printc_count == ctx.config.printc_count as u32 @@ -223,7 +226,10 @@ impl SystemState { *printc_count = 0; tx.new_line(); } - tx.printrc(&format!("{name}[{no:3}]")); + tx.printrc(&format!( + "{name}[{no:3}]", + name = ctx.var.resolve_key(train) + )); *printc_count += 1; } @@ -235,6 +241,7 @@ impl SystemState { input_int(tx) } 5 => { + let train = ctx.var.interner().get_or_intern("TRAIN"); let no = ctx.pop_int()?; ctx.var.set_result(no); @@ -242,7 +249,7 @@ impl SystemState { Ok(no) => ctx .header_info .var_name_var - .get("TRAIN") + .get(&train) .map(|v| v.contains_key(&no)) .unwrap_or(false), _ => false, diff --git a/crates/erars-vm/src/terminal_vm.rs b/crates/erars-vm/src/terminal_vm.rs index 43aaf952..ab71a954 100644 --- a/crates/erars-vm/src/terminal_vm.rs +++ b/crates/erars-vm/src/terminal_vm.rs @@ -5,13 +5,13 @@ use std::{ path::{Path, PathBuf}, }; -use crate::context::FunctionIdentifier; use crate::*; +use crate::{context::FunctionIdentifier, variable::StrKeyLike}; use anyhow::{anyhow, bail, Result}; use arrayvec::ArrayVec; use erars_ast::{ BeginType, BinaryOperator, BuiltinCommand, BuiltinMethod, BuiltinVariable, EventType, - PrintFlags, UnaryOperator, Value, + PrintFlags, StrKey, UnaryOperator, Value, }; use erars_compiler::{Instruction, ParserContext, ReplaceInfo}; use erars_ui::{FontStyle, InputRequest, InputRequestType, Timeout, VirtualConsole}; @@ -36,7 +36,7 @@ enum InstructionWorkflow { Exit, Goto(u32), GotoLabel { - label: String, + label: StrKey, is_try: bool, }, Return, @@ -77,7 +77,7 @@ impl TerminalVm { mut cursor: usize, ) -> Result { let insts = body.body(); - let func_name = func_identifier.name(); + let func_name = func_identifier.get_key(&ctx.var); while let Some(inst) = insts.get(cursor) { cursor += 1; @@ -85,6 +85,7 @@ impl TerminalVm { log::trace!( "[{func_name}] `{inst:?}[{cursor}]`, stack: {stack:?}, call_stack: {call_stack:?}", + func_name = ctx.var.resolve_key(func_name), stack = ctx.stack(), call_stack = ctx.call_stack(), ); @@ -95,7 +96,7 @@ impl TerminalVm { Ok(Goto(pos)) => { cursor = pos as usize; } - Ok(GotoLabel { label, is_try }) => match body.goto_labels().get(label.as_str()) { + Ok(GotoLabel { label, is_try }) => match body.goto_labels().get(&label) { Some(pos) => { cursor = *pos as usize; } @@ -103,7 +104,10 @@ impl TerminalVm { if is_try { ctx.push(false); } else { - bail!("Label {label} is not founded"); + bail!( + "Label {label} is not founded", + label = ctx.var.resolve_key(label) + ); } } }, @@ -210,18 +214,21 @@ impl TerminalVm { fn call_internal( &self, - label: &str, + label: StrKey, args: &[Value], tx: &mut VirtualConsole, ctx: &mut VmContext, body: &FunctionBody, ) -> Result { - log::trace!("CALL {label}({args:?})"); + log::trace!( + "CALL {label}({args:?})", + label = ctx.var.interner().resolve(&label) + ); let mut args = args.iter().cloned(); for (var_idx, default_value, arg_indices) in body.args().iter() { - let (info, var) = ctx.var.get_maybe_local_var(label, var_idx)?; + let (info, var) = ctx.var.get_maybe_local_var(label, *var_idx)?; let var = var.assume_normal(); let idx = info.calculate_single_idx(arg_indices).1; @@ -242,7 +249,7 @@ impl TerminalVm { } } - let ret = self.run_body(FunctionIdentifier::Normal(label.into()), body, tx, ctx, 0)?; + let ret = self.run_body(FunctionIdentifier::Normal(label), body, tx, ctx, 0)?; Ok(ret) } @@ -266,8 +273,11 @@ impl TerminalVm { tx: &mut VirtualConsole, ctx: &mut VmContext, ) -> Result> { - match self.dic.get_func_opt(label) { - Some(body) => self.call_internal(label, args, tx, ctx, body).map(Some), + match ctx.var.interner().get(label) { + Some(label) => match self.dic.get_func_opt(label) { + Some(body) => self.call_internal(label, args, tx, ctx, body).map(Some), + None => Ok(None), + }, None => Ok(None), } } @@ -300,7 +310,7 @@ impl TerminalVm { log::info!("{stack:?}"); match stack.func_name { FunctionIdentifier::Normal(name) => { - let body = self.dic.get_func(&name).unwrap(); + let body = self.dic.get_func(name)?; match self.run_body( FunctionIdentifier::Normal(name), body, @@ -423,7 +433,7 @@ impl TerminalVm { report_error!( tx, "At function {func} {file}@{line}", - func = call_stack.func_name.name(), + func = call_stack.func_name.resolve_key(&ctx.var), file = call_stack.file_path, line = call_stack.script_position.line ); diff --git a/crates/erars-vm/src/terminal_vm/executor.rs b/crates/erars-vm/src/terminal_vm/executor.rs index 883e2216..4cb8d78f 100644 --- a/crates/erars-vm/src/terminal_vm/executor.rs +++ b/crates/erars-vm/src/terminal_vm/executor.rs @@ -1,3 +1,5 @@ +use crate::variable::KnownVariableNames as Var; + use super::*; macro_rules! ret_set_state { @@ -16,7 +18,7 @@ macro_rules! get_arg { (@var $arg:expr) => { match $arg.next() { Some(LocalValue::VarRef(r)) => r, - Some(LocalValue::Value(_)) => bail!("매개변수가 VarRef가 아닙니다"), + Some(_) => bail!("매개변수가 VarRef가 아닙니다"), None => bail!("매개변수가 부족합니다"), } }; @@ -25,8 +27,7 @@ macro_rules! get_arg { }; (@opt @value $arg:expr, $ctx:expr) => { match $arg.next() { - Some(LocalValue::VarRef(r)) => Some($ctx.read_var_ref(&r)?), - Some(LocalValue::Value(v)) => Some(v), + Some(v) => Some($ctx.reduce_local_value(v)?), None => None, } }; @@ -40,16 +41,16 @@ macro_rules! get_arg { pub(super) fn run_instruction( vm: &TerminalVm, - func_name: &str, + func_name: StrKey, inst: &Instruction, tx: &mut VirtualConsole, ctx: &mut VmContext, ) -> Result { match inst { + Instruction::Nop => {} Instruction::ReportPosition(pos) => ctx.update_position(pos.clone()), Instruction::LoadInt(n) => ctx.push(*n), - Instruction::LoadStr(s) => ctx.push(s.to_string()), - Instruction::Nop => {} + Instruction::LoadStr(s) => ctx.push_strkey(*s), Instruction::Pop => drop(ctx.pop()?), Instruction::Duplicate => ctx.dup(), Instruction::DuplicatePrev => ctx.dup_prev(), @@ -63,7 +64,11 @@ pub(super) fn run_instruction( } Instruction::EvalFormString => { let form = ctx.pop_str()?; - let parser_ctx = ParserContext::new(ctx.header_info.clone(), "FORMS.ERB".into()); + let parser_ctx = ParserContext::new( + ctx.var.clone_interner(), + ctx.header_info.clone(), + "FORMS.ERB".into(), + ); let expr = erars_compiler::normal_form_str(&parser_ctx)(&form).unwrap().1; let insts = erars_compiler::compile_expr(expr).unwrap(); @@ -76,26 +81,29 @@ pub(super) fn run_instruction( } Instruction::GotoLabel => { return Ok(InstructionWorkflow::GotoLabel { - label: ctx.pop_str()?, + label: ctx.pop_strkey()?, is_try: false, }); } Instruction::TryGotoLabel => { return Ok(InstructionWorkflow::GotoLabel { - label: ctx.pop_str()?, + label: ctx.pop_strkey()?, is_try: true, }) } Instruction::LoadExternVarRef(c) => { - let func_extern = ctx.pop_str()?; - let name = ctx.pop_str()?; + let func_extern = ctx.pop_strkey()?; + let name = ctx.pop_strkey()?; let args = ctx.take_arg_list(None, *c)?; ctx.push_var_ref(name, func_extern, args); } Instruction::LoadVarRef(c) => { - let name = ctx.pop_str()?; - let args = ctx.take_arg_list(Some(&name), *c)?; - ctx.push_var_ref(name, func_name.to_string(), args); + let name = ctx.pop_strkey()?; + let args = ctx.take_arg_list(Some(name), *c)?; + ctx.push_var_ref(name, func_name, args); + } + Instruction::LoadCountVarRef => { + ctx.push_var_ref(ctx.var.known_key(Var::Count), func_name, ArrayVec::new()); } Instruction::StoreVar => { let var_ref = ctx.pop_var_ref()?; @@ -282,13 +290,17 @@ pub(super) fn run_instruction( | PalamName | SourceName | StainName | TcvarName | GlobalName | GlobalsName | SaveStrName => { let name = <&str>::from(var).strip_suffix("NAME").unwrap(); + let name = ctx.var.interner().get_or_intern(name); let arg = args[0] as u32; - ctx.header_info - .var_name_var - .get(name) - .and_then(|d| Some(d.get(&arg)?.as_str())) - .unwrap_or("") - .into() + Value::String( + ctx.header_info + .var_name_var + .get(&name) + .and_then(|d| { + Some(ctx.var.interner().resolve(d.get(&arg)?).to_string()) + }) + .unwrap_or_default(), + ) } Rand => { let max = args[0]; @@ -528,8 +540,8 @@ pub(super) fn run_instruction( let start = get_arg!(@opt @usize: args, ctx).unwrap_or(0); let end = get_arg!(@opt @usize: args, ctx); - let target = ctx.var.read_int("TARGET", &[])?; - let var = ctx.var.get_maybe_local_var(func_name, &var_ref.name)?.1; + let target = ctx.var.read_int(Var::Target, &[])?; + let var = ctx.var.get_maybe_local_var(func_name, var_ref.name)?.1; let var = match var { UniformVariable::Character(cvar) => { @@ -831,13 +843,15 @@ pub(super) fn run_instruction( match com { BuiltinCommand::UpCheck => { - let names = ctx.header_info.var_name_var.get("PALAM").unwrap(); - let target = ctx.var.read_int("TARGET", &[])?.try_into()?; + let palam = ctx.var.known_key(Var::Palam); + let names = ctx.header_info.var_name_var.get(&palam).unwrap(); + let target = ctx.var.read_int(Var::Target, &[])?.try_into()?; ctx.var.upcheck(tx, target, names)?; } BuiltinCommand::CUpCheck => { + let palam = ctx.var.known_key(Var::Palam); let target = get_arg!(@usize: args, ctx); - let names = ctx.header_info.var_name_var.get("PALAM").unwrap(); + let names = ctx.header_info.var_name_var.get(&palam).unwrap(); ctx.var.cupcheck(tx, target, names)?; } BuiltinCommand::Restart => { @@ -870,9 +884,9 @@ pub(super) fn run_instruction( let target = if let Some(idx) = v.idxs.first().copied() { idx } else { - ctx.var.read_int("TARGET", &[])?.try_into()? + ctx.var.read_int(Var::Target, &[])?.try_into()? }; - let (info, var) = ctx.var.get_maybe_local_var(&v.func_name, &v.name)?; + let (info, var) = ctx.var.get_maybe_local_var(v.func_name, v.name)?; let var = var.as_vm_var(target); if info.is_str { @@ -930,7 +944,7 @@ pub(super) fn run_instruction( let value = get_arg!(@opt @value args, ctx); let start = get_arg!(@opt @usize: args, ctx); - let (info, var) = ctx.var.get_var(&var.name)?; + let (info, var) = ctx.var.get_var(var.name)?; let value = value.unwrap_or_else(|| { if info.is_str { @@ -987,12 +1001,8 @@ pub(super) fn run_instruction( let mut result_idx = 0usize; let mut results_idx = 0usize; - let args: ArrayVec<_, 8> = args - .map(|v| match v { - LocalValue::Value(v) => Ok(v), - LocalValue::VarRef(v) => ctx.read_var_ref(&v), - }) - .try_collect()?; + let args: ArrayVec<_, 8> = + args.map(|v| ctx.reduce_local_value(v)).try_collect()?; let ((_, result), (_, results)) = ctx.var.get_var2("RESULT", "RESULTS").unwrap(); diff --git a/crates/erars-vm/src/variable.rs b/crates/erars-vm/src/variable.rs index ee538edd..728497ea 100644 --- a/crates/erars-vm/src/variable.rs +++ b/crates/erars-vm/src/variable.rs @@ -1,11 +1,12 @@ use std::{ collections::{BTreeMap, BTreeSet}, - sync::Arc, fmt::Debug, + fmt::Debug, + sync::Arc, }; use anyhow::{anyhow, bail, Result}; -use enum_map::{EnumMap, Enum}; -use erars_ast::{Interner, StrKey, Value, VariableInfo}; +use enum_map::{Enum, EnumMap}; +use erars_ast::{EventType, Interner, StrKey, Value, VariableInfo}; use erars_compiler::{CharacterTemplate, HeaderInfo, ReplaceInfo}; use hashbrown::HashMap; use rand::SeedableRng; @@ -14,14 +15,16 @@ use rayon::prelude::*; use serde::{Deserialize, Serialize}; use erars_ui::VirtualConsole; -use strum::{IntoStaticStr, Display}; +use strum::{Display, IntoStaticStr}; + +use crate::context::FunctionIdentifier; macro_rules! set_var { - ($self:expr, $name:expr, $value:expr) => { - *$self.ref_int($name, &[])? = $value; + ($self:expr, $name:ident, $value:expr) => { + *$self.ref_int(KnownVariableNames::$name, &[])? = $value; }; - (@all $self:expr, $name:expr, $value:expr) => { - match $self.get_var($name)?.1 { + (@all $self:expr, $name:ident, $value:expr) => { + match $self.get_var(KnownVariableNames::$name)?.1 { UniformVariable::Character(ref mut cvar) => { for var in cvar { var.as_int()?.fill($value); @@ -61,6 +64,7 @@ pub struct VariableStorage { variables: HashMap, local_variables: HashMap)>>, known_variables: EnumMap, + event_keys: EnumMap, } impl VariableStorage { @@ -68,14 +72,10 @@ impl VariableStorage { let mut variables = HashMap::new(); for (k, v) in infos { - variables.insert( - *k, - (v.clone(), UniformVariable::new(v)), - ); + variables.insert(*k, (v.clone(), UniformVariable::new(v))); } Self { - interner, character_len: 0, rng: ChaCha20Rng::from_entropy(), variables, @@ -83,14 +83,37 @@ impl VariableStorage { known_variables: enum_map::enum_map! { v => interner.get_or_intern_static(<&str>::from(v)), }, + event_keys: enum_map::enum_map! { + v => interner.get_or_intern_static(<&str>::from(v)), + }, + interner, } } + pub fn clone_interner(&self) -> Arc { + self.interner.clone() + } + + #[inline] + pub fn interner(&self) -> &Interner { + &self.interner + } + + #[inline] + pub fn event_key(&self, ty: EventType) -> StrKey { + self.event_keys[ty] + } + #[inline] pub fn known_key(&self, var: KnownVariableNames) -> StrKey { self.known_variables[var] } + #[inline] + pub fn resolve_key(&self, key: StrKey) -> &str { + self.interner.resolve(&key) + } + fn load_variables( &mut self, variables: HashMap, @@ -98,7 +121,7 @@ impl VariableStorage { ) { for (k, (info, var)) in variables { let (now_info, now_var) = - match self.interner.get(k).and_then(|k| self.variables.get_mut(&k)) { + match self.interner.get(&k).and_then(|k| self.variables.get_mut(&k)) { Some(v) => v, _ => { log::warn!("Ignore non existing variable {k}"); @@ -176,8 +199,8 @@ impl VariableStorage { &self, is_global: bool, ) -> ( - HashMap, - HashMap>, + HashMap, + HashMap)>>, ) { let variables = self .variables @@ -267,6 +290,7 @@ impl VariableStorage { palam: &mut [i64], up: &mut [i64], down: &mut [i64], + interner: &Interner, ) -> Result<()> { itertools::multizip((palam.iter_mut(), up.iter_mut(), down.iter_mut())) .enumerate() @@ -275,7 +299,10 @@ impl VariableStorage { return; } - let name = palam_name.get(&(no as u32)).map(|s| s.as_str()).unwrap_or(""); + let name = palam_name + .get(&(no as u32)) + .map(|s| interner.resolve(s)) + .unwrap_or(""); tx.print(format!("{name} {p}")); @@ -305,13 +332,18 @@ impl VariableStorage { idx: usize, palam_name: &BTreeMap, ) -> Result<()> { - let (palam, up, down) = self.get_var3("PALAM", "UP", "DOWN")?; + let interner = self.interner.clone(); + let (palam, up, down) = self.get_var3( + KnownVariableNames::Palam, + KnownVariableNames::Up, + KnownVariableNames::Down, + )?; let palam = palam.1.assume_chara(idx).as_int()?; let up = up.1.assume_normal().as_int()?; let down = down.1.assume_normal().as_int()?; - Self::upcheck_internal(tx, palam_name, palam, up, down) + Self::upcheck_internal(tx, palam_name, palam, up, down, &interner) } pub fn cupcheck( @@ -320,37 +352,42 @@ impl VariableStorage { idx: usize, palam_name: &BTreeMap, ) -> Result<()> { - let (palam, up, down) = self.get_var3("PALAM", "CUP", "CDOWN")?; + let interner = self.interner.clone(); + let (palam, up, down) = self.get_var3( + KnownVariableNames::Palam, + KnownVariableNames::Cup, + KnownVariableNames::Cdown, + )?; let palam = palam.1.assume_chara(idx).as_int()?; let up = up.1.assume_chara(idx).as_int()?; let down = down.1.assume_chara(idx).as_int()?; - Self::upcheck_internal(tx, palam_name, palam, up, down) + Self::upcheck_internal(tx, palam_name, palam, up, down, &interner) } pub fn prepare_train_data(&mut self) -> Result<()> { - self.reset_var("UP")?; - self.reset_var("DOWN")?; - self.reset_var("LOSEBASE")?; - self.reset_var("CUP")?; - self.reset_var("CDOWN")?; - self.reset_var("DOWNBASE")?; + self.reset_var(KnownVariableNames::Up)?; + self.reset_var(KnownVariableNames::Down)?; + self.reset_var(KnownVariableNames::LoseBase)?; + self.reset_var(KnownVariableNames::Cup)?; + self.reset_var(KnownVariableNames::Cdown)?; + self.reset_var(KnownVariableNames::DownBase)?; Ok(()) } pub fn reset_train_data(&mut self) -> Result<()> { - set_var!(self, "ASSIPLAY", 0); - set_var!(self, "PREVCOM", -1); - set_var!(self, "NEXTCOM", -1); + set_var!(self, AssiPlay, 0); + set_var!(self, PrevCom, -1); + set_var!(self, NextCom, -1); - set_var!(@all self, "TFLAG", 0); - set_var!(@all self, "TEQUIP", 0); - set_var!(@all self, "PALAM", 0); - set_var!(@all self, "STAIN", 0); - set_var!(@all self, "SOURCE", 0); - set_var!(@all self, "GOTJUEL", 0); + set_var!(@all self, Tflag, 0); + set_var!(@all self, Tequip, 0); + set_var!(@all self, Palam, 0); + set_var!(@all self, Stain, 0); + set_var!(@all self, Source, 0); + set_var!(@all self, GotJuel, 0); Ok(()) } @@ -445,7 +482,12 @@ impl VariableStorage { Ok(var.as_int()?[idx]) } - pub fn read_local_int(&mut self, func_name: impl StrKeyLike, name: impl StrKeyLike, args: &[usize]) -> Result { + pub fn read_local_int( + &mut self, + func_name: impl StrKeyLike, + name: impl StrKeyLike, + args: &[usize], + ) -> Result { let (_, var, idx) = self.index_local_var(func_name, name, args)?; Ok(var.as_int()?[idx]) } @@ -489,8 +531,9 @@ impl VariableStorage { let vm_var = match var { UniformVariable::Character(cvar) => { let c_idx = c_idx.unwrap_or_else(|| target as usize); - cvar.get_mut(c_idx) - .ok_or_else(|| anyhow!("Variable {name:?} Character index {c_idx} not exists"))? + cvar.get_mut(c_idx).ok_or_else(|| { + anyhow!("Variable {name:?} Character index {c_idx} not exists") + })? } UniformVariable::Normal(var) => var, }; @@ -504,6 +547,9 @@ impl VariableStorage { name: impl StrKeyLike, args: &[usize], ) -> Result<(&mut VariableInfo, &mut VmVariable, usize)> { + let func_name = func_name.get_key(self); + let name = name.get_key(self); + let target = self.read_int("TARGET", &[])?; let (info, var) = self.get_local_var(func_name, name)?; @@ -514,7 +560,7 @@ impl VariableStorage { UniformVariable::Character(cvar) => { let c_idx = c_idx.unwrap_or(target as usize); cvar.get_mut(c_idx).ok_or_else(|| { - anyhow!("Variable {name}@{func_name} Character index {c_idx} not exists") + anyhow!("Variable {name:?}@{func_name:?} Character index {c_idx} not exists",) })? } UniformVariable::Normal(var) => var, @@ -541,11 +587,13 @@ impl VariableStorage { func_name: impl StrKeyLike, var: impl StrKeyLike, ) -> Result<(&mut VariableInfo, &mut UniformVariable)> { + let func_name = func_name.get_key(self); + let var = var.get_key(self); let (info, var) = self .local_variables - .get_mut(&func_name.get_key(self)) + .get_mut(&func_name) .unwrap() - .get_mut(&var.get_key(self)) + .get_mut(&var) .ok_or_else(|| anyhow!("Variable {:?} is not exists", var))?; if var.is_none() { @@ -582,7 +630,7 @@ impl VariableStorage { } pub fn reset_var(&mut self, var: impl StrKeyLike) -> Result<()> { - let (info, var) = self.get_var(&var.get_key(self))?; + let (info, var) = self.get_var(var)?; if info.is_str { match var { @@ -603,10 +651,14 @@ impl VariableStorage { Ok(()) } - pub fn get_var(&mut self, var: impl StrKeyLike) -> Result<(&mut VariableInfo, &mut UniformVariable)> { + pub fn get_var( + &mut self, + var: impl StrKeyLike, + ) -> Result<(&mut VariableInfo, &mut UniformVariable)> { + let var = var.get_key(self); let (l, r) = self .variables - .get_mut(&var.get_key(self)) + .get_mut(&var) .ok_or_else(|| anyhow!("Variable {var:?} is not exists"))?; Ok((l, r)) @@ -638,7 +690,10 @@ impl VariableStorage { (&mut VariableInfo, &mut UniformVariable), (&mut VariableInfo, &mut UniformVariable), )> { - match self.variables.get_many_mut([&v1.get_key(self), &v2.get_key(self), &v3.get_key(self)]) { + match self + .variables + .get_many_mut([&v1.get_key(self), &v2.get_key(self), &v3.get_key(self)]) + { Some([(l1, r1), (l2, r2), (l3, r3)]) => Ok(((l1, r1), (l2, r2), (l3, r3))), None => { bail!("Variable {v1:?} or {v2:?} or {v3:?} is not exists"); @@ -684,7 +739,7 @@ impl VariableStorage { } pub fn get_chara(&mut self, target: i64) -> Result> { - let (_, no_var) = self.variables.get_mut("NO").unwrap(); + let (_, no_var) = self.get_var(KnownVariableNames::No)?; match no_var { UniformVariable::Character(c) => { for (idx, var) in c.iter_mut().enumerate() { @@ -908,11 +963,15 @@ impl UniformVariable { #[derive(Debug, Clone, Copy, PartialEq, Eq, Enum, IntoStaticStr, Display)] #[strum(serialize_all = "UPPERCASE")] pub enum KnownVariableNames { + No, Count, NextCom, PrevCom, - CurrentCom, + SelectCom, + Master, Target, + Assi, + AssiPlay, Local, LocalS, Arg, @@ -927,10 +986,27 @@ pub enum KnownVariableNames { Down, Cup, Cdown, + Stain, + #[allow(non_camel_case_types)] + SaveData_Text, + + Base, + DownBase, + LoseBase, + + Tflag, + Tequip, + Source, + Juel, + GotJuel, } -trait StrKeyLike: Debug + Copy { +pub trait StrKeyLike: Debug + Copy { fn get_key(self, var: &VariableStorage) -> StrKey; + + fn resolve_key(self, var: &VariableStorage) -> &str { + var.resolve_key(self.get_key(var)) + } } impl StrKeyLike for StrKey { @@ -940,6 +1016,12 @@ impl StrKeyLike for StrKey { } } +impl<'a> StrKeyLike for &'a str { + fn get_key(self, var: &VariableStorage) -> StrKey { + var.interner().get_or_intern(self) + } +} + impl StrKeyLike for KnownVariableNames { #[inline(always)] fn get_key(self, var: &VariableStorage) -> StrKey { @@ -947,3 +1029,18 @@ impl StrKeyLike for KnownVariableNames { } } +impl StrKeyLike for EventType { + #[inline(always)] + fn get_key(self, var: &VariableStorage) -> StrKey { + var.event_key(self) + } +} + +impl StrKeyLike for FunctionIdentifier { + fn get_key(self, var: &VariableStorage) -> StrKey { + match self { + FunctionIdentifier::Normal(key) => key, + FunctionIdentifier::Event(ty, _) => ty.get_key(var), + } + } +} From 8dbba18c390f67e3389a6e5bcad4fb9f9cb20ea2 Mon Sep 17 00:00:00 2001 From: Riey Date: Fri, 14 Oct 2022 11:29:49 +0900 Subject: [PATCH 4/8] Use global interner --- Cargo.lock | 1 + crates/erars-ast/Cargo.toml | 1 + crates/erars-ast/src/ast.rs | 22 ++++---- crates/erars-ast/src/event.rs | 20 ++++++- crates/erars-ast/src/lib.rs | 62 ++++++++++++++++++++- crates/erars-ast/src/variable.rs | 9 ++- crates/erars-compiler/src/parser.rs | 25 +++++---- crates/erars-stdio/src/main.rs | 57 +++---------------- crates/erars-vm/src/context.rs | 10 +--- crates/erars-vm/src/function.rs | 9 ++- crates/erars-vm/src/system_func.rs | 1 - crates/erars-vm/src/terminal_vm/executor.rs | 6 +- crates/erars-vm/src/variable.rs | 23 ++++---- 13 files changed, 136 insertions(+), 110 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index d9bed226..a29d1356 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -650,6 +650,7 @@ dependencies = [ "lasso", "num-derive", "num-traits", + "once_cell", "option_set", "ordered-float", "serde", diff --git a/crates/erars-ast/Cargo.toml b/crates/erars-ast/Cargo.toml index 319a2d24..99bb2820 100644 --- a/crates/erars-ast/Cargo.toml +++ b/crates/erars-ast/Cargo.toml @@ -17,6 +17,7 @@ smol_str = { version = "0.1.23", features = ["serde"] } strum = { version = "0.24.1", features = ["derive"] } anyhow = { version = "1" } lasso = { version = "0.6.0", features = ["multi-threaded", "ahasher", "serialize"] } +once_cell = "1.15.0" [dev-dependencies] k9 = "0.11.1" diff --git a/crates/erars-ast/src/ast.rs b/crates/erars-ast/src/ast.rs index 60f34d96..22f4c0db 100644 --- a/crates/erars-ast/src/ast.rs +++ b/crates/erars-ast/src/ast.rs @@ -2,7 +2,7 @@ use std::fmt; use bitflags::bitflags; use ordered_float::NotNan; -use serde::{Serialize, Deserialize}; +use serde::{Deserialize, Serialize}; use smol_str::SmolStr; use strum::{Display, EnumString}; @@ -11,7 +11,7 @@ use crate::{ EventType, Interner, LocalVariable, StrKey, UnaryOperator, Value, Variable, }; -#[derive(Clone, Debug, PartialEq, Eq)] +#[derive(Clone, Debug, PartialEq, Eq, Serialize, Deserialize)] pub enum Stmt { Label(StrKey), SelectCase( @@ -54,7 +54,7 @@ pub enum Stmt { Alignment(Alignment), } -#[derive(Clone, Debug, PartialEq, Eq)] +#[derive(Clone, Debug, PartialEq, Eq, Serialize, Deserialize)] pub struct StmtWithPos(pub Stmt, pub ScriptPosition); #[derive(Clone, Copy, Default, Debug, PartialEq, Eq, Serialize, Deserialize)] @@ -69,13 +69,13 @@ impl fmt::Display for ScriptPosition { } } -#[derive(Clone, Debug, PartialEq, Eq)] +#[derive(Clone, Debug, PartialEq, Eq, Serialize, Deserialize)] pub struct Function { pub header: FunctionHeader, pub body: Vec, } -#[derive(Clone, Debug, PartialEq, Eq)] +#[derive(Clone, Debug, PartialEq, Eq, Serialize, Deserialize)] pub struct FunctionHeader { pub file_path: SmolStr, pub name: StrKey, @@ -83,7 +83,7 @@ pub struct FunctionHeader { pub infos: Vec, } -#[derive(Clone, Debug, PartialEq, Eq)] +#[derive(Clone, Debug, PartialEq, Eq, Serialize, Deserialize)] pub enum FunctionInfo { EventFlag(EventFlags), LocalSize(usize), @@ -93,7 +93,7 @@ pub enum FunctionInfo { FunctionS, } -#[derive(Clone, Debug, PartialEq, Eq)] +#[derive(Clone, Debug, PartialEq, Eq, Serialize, Deserialize)] pub enum Expr { String(StrKey), Int(i64), @@ -149,14 +149,14 @@ impl Expr { } } -#[derive(Clone, Debug, PartialEq, Eq)] +#[derive(Clone, Debug, PartialEq, Eq, Serialize, Deserialize)] pub enum SelectCaseCond { Single(Expr), To(Expr, Expr), Is(BinaryOperator, Expr), } -#[derive(Clone, PartialEq, Eq)] +#[derive(Clone, PartialEq, Eq, Serialize, Deserialize)] pub struct FormExpr { pub expr: Expr, pub padding: Option, @@ -169,7 +169,7 @@ impl fmt::Debug for FormExpr { } } -#[derive(Clone, PartialEq, Eq, Default)] +#[derive(Clone, PartialEq, Eq, Default, Serialize, Deserialize)] pub struct FormText { pub first: StrKey, pub other: Vec<(FormExpr, StrKey)>, @@ -223,7 +223,7 @@ option_set::option_set! { } } -#[derive(Copy, Clone, Debug, Eq, Hash, PartialEq, EnumString, Display)] +#[derive(Copy, Clone, Debug, Eq, Hash, PartialEq, EnumString, Display, Serialize, Deserialize)] pub enum BeginType { #[strum(to_string = "TITLE")] Title, diff --git a/crates/erars-ast/src/event.rs b/crates/erars-ast/src/event.rs index b5a5830c..e821f956 100644 --- a/crates/erars-ast/src/event.rs +++ b/crates/erars-ast/src/event.rs @@ -1,7 +1,8 @@ use enum_map::Enum; +use serde::{Deserialize, Serialize}; use strum::{Display, EnumString, IntoStaticStr}; -#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)] +#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash, Serialize, Deserialize)] pub struct Event { pub ty: EventType, pub flags: EventFlags, @@ -37,7 +38,7 @@ impl Event { } } -#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)] +#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash, Serialize, Deserialize)] pub enum EventFlags { None, Pre, @@ -45,7 +46,20 @@ pub enum EventFlags { Single, } -#[derive(Enum, Clone, Copy, Debug, PartialEq, Eq, Hash, Display, EnumString, IntoStaticStr)] +#[derive( + Enum, + Clone, + Copy, + Debug, + PartialEq, + Eq, + Hash, + Display, + EnumString, + IntoStaticStr, + Serialize, + Deserialize, +)] pub enum EventType { #[strum(to_string = "EVENTFIRST")] First, diff --git a/crates/erars-ast/src/lib.rs b/crates/erars-ast/src/lib.rs index ae5b729f..116deced 100644 --- a/crates/erars-ast/src/lib.rs +++ b/crates/erars-ast/src/lib.rs @@ -15,9 +15,69 @@ pub use ordered_float::NotNan; pub use value::Value; pub use variable::*; -pub type StrKey = lasso::Spur; +use once_cell::sync::Lazy; + pub type Interner = lasso::ThreadedRodeo; +pub static GLOBAL_INTERNER: Lazy = Lazy::new(|| Interner::new()); + +#[derive(Clone, Copy, Default, PartialEq, Eq, PartialOrd, Ord, Hash)] +#[repr(transparent)] +pub struct StrKey(lasso::Spur); + +impl StrKey { + pub fn resolve(self) -> &'static str { + GLOBAL_INTERNER.resolve(&self) + } + + pub fn new(s: &str) -> Self { + GLOBAL_INTERNER.get_or_intern(s) + } +} + +impl std::fmt::Debug for StrKey { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + f.write_str(GLOBAL_INTERNER.resolve(&self)) + } +} + +impl std::fmt::Display for StrKey { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + std::fmt::Debug::fmt(self, f) + } +} + +impl serde::Serialize for StrKey { + fn serialize(&self, serializer: S) -> Result + where + S: serde::Serializer, + { + self.resolve().serialize(serializer) + } +} + +impl<'de> serde::Deserialize<'de> for StrKey { + fn deserialize(deserializer: D) -> Result + where + D: serde::Deserializer<'de>, + { + let s = String::deserialize(deserializer)?; + Ok(Self::new(&s)) + } +} + +unsafe impl lasso::Key for StrKey { + #[inline(always)] + fn into_usize(self) -> usize { + self.0.into_usize() + } + + #[inline(always)] + fn try_from_usize(int: usize) -> Option { + lasso::Spur::try_from_usize(int).map(Self) + } +} + pub fn var_name_alias(var: &str) -> &str { match var { "MAXBASE" | "UPBASE" | "DOWNBASE" | "LOSEBASE" => "BASE", diff --git a/crates/erars-ast/src/variable.rs b/crates/erars-ast/src/variable.rs index 8b905866..02dc7630 100644 --- a/crates/erars-ast/src/variable.rs +++ b/crates/erars-ast/src/variable.rs @@ -3,7 +3,9 @@ use serde::{Deserialize, Serialize}; use strum::{Display, EnumString, IntoStaticStr}; /// This variables are readonly system variables -#[derive(Clone, Copy, Debug, PartialEq, Eq, Display, EnumString, IntoStaticStr)] +#[derive( + Clone, Copy, Debug, PartialEq, Eq, Display, EnumString, IntoStaticStr, Serialize, Deserialize, +)] #[strum(serialize_all = "UPPERCASE")] pub enum BuiltinVariable { AblName, @@ -61,20 +63,21 @@ pub enum BuiltinVariable { GamebaseInfo, } -#[derive(Clone, Debug, PartialEq, Eq)] +#[derive(Clone, Debug, PartialEq, Eq, Serialize, Deserialize)] pub struct Variable { pub var: StrKey, pub func_extern: Option, pub args: Vec, } -#[derive(Clone, Debug, PartialEq, Eq)] +#[derive(Clone, Debug, PartialEq, Eq, Serialize, Deserialize)] pub struct LocalVariable { pub var: StrKey, pub info: VariableInfo, } #[derive(Clone, Default, Debug, PartialEq, Eq, Serialize, Deserialize)] +#[serde(default)] pub struct VariableInfo { pub is_chara: bool, pub is_str: bool, diff --git a/crates/erars-compiler/src/parser.rs b/crates/erars-compiler/src/parser.rs index b69dcbb8..5292d31e 100644 --- a/crates/erars-compiler/src/parser.rs +++ b/crates/erars-compiler/src/parser.rs @@ -1,11 +1,10 @@ mod csv; mod expr; -use enum_map::{Enum, EnumMap}; use erars_ast::{ Alignment, BeginType, BinaryOperator, BuiltinCommand, EventFlags, EventType, Expr, Function, FunctionHeader, FunctionInfo, Interner, ScriptPosition, Stmt, StmtWithPos, StrKey, Variable, - VariableInfo, + VariableInfo, GLOBAL_INTERNER, }; use erars_lexer::{ConfigToken, ErhToken, JumpType, PrintType, Token}; use hashbrown::{HashMap, HashSet}; @@ -19,7 +18,7 @@ use std::{ mem, sync::Arc, }; -use strum::{Display, EnumString, IntoStaticStr}; +use strum::{Display, EnumString}; pub use crate::error::{ParserError, ParserResult}; use crate::CompiledFunction; @@ -255,8 +254,9 @@ pub struct HeaderInfo { } impl HeaderInfo { - pub fn merge_chara_csv(&mut self, interner: &Interner, s: &str) -> ParserResult<()> { + pub fn merge_chara_csv(&mut self, s: &str) -> ParserResult<()> { let mut lex = Lexer::new(s); + let interner = &*GLOBAL_INTERNER; let mut template = CharacterTemplate::default(); macro_rules! define_keys { @@ -416,8 +416,9 @@ impl HeaderInfo { Ok(()) } - pub fn merge_name_csv(&mut self, interner: &Interner, var: &str, s: &str) -> ParserResult<()> { + pub fn merge_name_csv(&mut self, var: &str, s: &str) -> ParserResult<()> { let mut lex = Lexer::new(s); + let interner = &*GLOBAL_INTERNER; let var = interner.get_or_intern(var); let mut name_var = BTreeMap::new(); @@ -431,8 +432,9 @@ impl HeaderInfo { Ok(()) } - pub fn merge_item_csv(&mut self, interner: &Interner, s: &str) -> ParserResult<()> { + pub fn merge_item_csv(&mut self, s: &str) -> ParserResult<()> { let mut lex = Lexer::new(s); + let interner = &*GLOBAL_INTERNER; let var = interner.get_or_intern_static("ITEM"); while let Some((n, s, price)) = self::csv::name_item_line(&interner, &mut lex)? { @@ -444,8 +446,9 @@ impl HeaderInfo { Ok(()) } - pub fn merge_variable_size_csv(&mut self, interner: &Interner, s: &str) -> ParserResult<()> { + pub fn merge_variable_size_csv(&mut self, s: &str) -> ParserResult<()> { let mut lex = Lexer::new(s); + let interner = &*GLOBAL_INTERNER; while let Some((name, sizes)) = self::csv::variable_size_line(&mut lex)? { match name.as_str() { @@ -610,7 +613,7 @@ impl HeaderInfo { #[derive(Debug)] pub struct ParserContext { - pub interner: Arc, + pub interner: &'static Interner, pub header: Arc, pub local_strs: RefCell>, pub is_arg: Cell, @@ -621,14 +624,14 @@ pub struct ParserContext { impl Default for ParserContext { fn default() -> Self { - Self::new(Arc::default(), Arc::default(), "".into()) + Self::new(Arc::default(), "".into()) } } impl ParserContext { - pub fn new(interner: Arc, header: Arc, file_path: SmolStr) -> Self { + pub fn new(header: Arc, file_path: SmolStr) -> Self { Self { - interner, + interner: &*GLOBAL_INTERNER, header, file_path, local_strs: RefCell::default(), diff --git a/crates/erars-stdio/src/main.rs b/crates/erars-stdio/src/main.rs index a2774b20..d9a74fcc 100644 --- a/crates/erars-stdio/src/main.rs +++ b/crates/erars-stdio/src/main.rs @@ -1,10 +1,7 @@ mod stdio_frontend; -use std::{path::Path, time::Instant}; - use erars_ast::Value; use erars_loader::run_script; -use erars_vm::{ScriptSaveFormat, ScriptSaveFormatRef, TerminalVm, VmContext}; #[derive(clap::Parser)] #[clap(author, version, about)] @@ -28,19 +25,16 @@ struct Args { #[clap(long, help = "Don't print logs")] quite: bool, + // #[clap(long, help = "Save script file")] + // save: bool, - #[clap(long, help = "Save script file")] - save: bool, - - #[clap(long, help = "Load script file")] - load: bool, + // #[clap(long, help = "Load script file")] + // load: bool, } fn main() { use flexi_logger::*; - let time = Instant::now(); - let args: Args = clap::Parser::parse(); let _handle = if args.quite { @@ -72,45 +66,8 @@ fn main() { None => Vec::new(), }; - let (vm, mut ctx) = if args.load { - let format: ScriptSaveFormat = bincode::deserialize_from(std::io::BufReader::new( - std::fs::File::open("game.era").unwrap(), - )) - .unwrap(); - - log::info!("dic: {:?}", format.dic); - - todo!(); - - ( - TerminalVm { - dic: format.dic, - sav_path: Path::new(&args.target_path).join("sav"), - }, - VmContext::new(format.header_info.into(), format.config.into()), - ) - } else { - run_script(args.target_path, inputs).unwrap() - }; - - let diff = time.elapsed(); - println!("Game load done! {}ms elapsed", diff.as_millis()); + let (vm, mut ctx) = run_script(args.target_path, inputs).unwrap(); - if args.save { - let time = Instant::now(); - bincode::serialize_into( - &mut std::io::BufWriter::new(std::fs::File::create("game.era").unwrap()), - &ScriptSaveFormatRef { - dic: &vm.dic, - config: &ctx.config, - header_info: &ctx.header_info, - }, - ) - .unwrap(); - let diff = time.elapsed(); - println!("Save done! {}ms elapsed", diff.as_millis()); - } else { - let mut frontend = stdio_frontend::StdioFrontend::new(ctx.config.printc_width); - frontend.run(&vm, &mut ctx).unwrap(); - } + let mut frontend = stdio_frontend::StdioFrontend::new(ctx.config.printc_width); + frontend.run(&vm, &mut ctx).unwrap(); } diff --git a/crates/erars-vm/src/context.rs b/crates/erars-vm/src/context.rs index da44a02e..f7f9a4e5 100644 --- a/crates/erars-vm/src/context.rs +++ b/crates/erars-vm/src/context.rs @@ -4,7 +4,7 @@ use smol_str::SmolStr; use std::fmt; use std::sync::Arc; -use erars_ast::{BeginType, EventType, Interner, ScriptPosition, StrKey, Value, VariableInfo}; +use erars_ast::{BeginType, EventType, ScriptPosition, StrKey, Value, VariableInfo}; use erars_compiler::{EraConfig, HeaderInfo}; use crate::variable::StrKeyLike; @@ -41,13 +41,9 @@ pub struct VmContext { } impl VmContext { - pub fn new( - interner: Arc, - header_info: Arc, - config: Arc, - ) -> Self { + pub fn new(header_info: Arc, config: Arc) -> Self { let mut ret = Self { - var: VariableStorage::new(interner, &header_info.global_variables), + var: VariableStorage::new(&header_info.global_variables), header_info, state: vec![StateCallStack { state: (BeginType::Title.into()), diff --git a/crates/erars-vm/src/function.rs b/crates/erars-vm/src/function.rs index 080fcf0a..a4f98f10 100644 --- a/crates/erars-vm/src/function.rs +++ b/crates/erars-vm/src/function.rs @@ -1,10 +1,9 @@ -use std::sync::Arc; - use anyhow::{anyhow, Result}; use arrayvec::ArrayVec; use enum_map::EnumMap; use erars_ast::Interner; use erars_ast::StrKey; +use erars_ast::GLOBAL_INTERNER; use erars_compiler::DefaultLocalVarSize; use hashbrown::HashMap; use smol_str::SmolStr; @@ -93,15 +92,15 @@ impl EventCollection { #[derive(Clone, Debug, PartialEq, Eq)] pub struct FunctionDic { - pub interner: Arc, + pub interner: &'static Interner, pub normal: HashMap, pub event: EnumMap, } impl FunctionDic { - pub fn new(interner: Arc) -> Self { + pub fn new() -> Self { Self { - interner, + interner: &*GLOBAL_INTERNER, normal: HashMap::new(), event: EnumMap::default(), } diff --git a/crates/erars-vm/src/system_func.rs b/crates/erars-vm/src/system_func.rs index 2a301506..71acb682 100644 --- a/crates/erars-vm/src/system_func.rs +++ b/crates/erars-vm/src/system_func.rs @@ -228,7 +228,6 @@ impl SystemState { } tx.printrc(&format!( "{name}[{no:3}]", - name = ctx.var.resolve_key(train) )); *printc_count += 1; } diff --git a/crates/erars-vm/src/terminal_vm/executor.rs b/crates/erars-vm/src/terminal_vm/executor.rs index 4cb8d78f..2c1fec9d 100644 --- a/crates/erars-vm/src/terminal_vm/executor.rs +++ b/crates/erars-vm/src/terminal_vm/executor.rs @@ -64,11 +64,7 @@ pub(super) fn run_instruction( } Instruction::EvalFormString => { let form = ctx.pop_str()?; - let parser_ctx = ParserContext::new( - ctx.var.clone_interner(), - ctx.header_info.clone(), - "FORMS.ERB".into(), - ); + let parser_ctx = ParserContext::new(ctx.header_info.clone(), "FORMS.ERB".into()); let expr = erars_compiler::normal_form_str(&parser_ctx)(&form).unwrap().1; let insts = erars_compiler::compile_expr(expr).unwrap(); diff --git a/crates/erars-vm/src/variable.rs b/crates/erars-vm/src/variable.rs index 728497ea..f1bff6b8 100644 --- a/crates/erars-vm/src/variable.rs +++ b/crates/erars-vm/src/variable.rs @@ -1,12 +1,11 @@ use std::{ collections::{BTreeMap, BTreeSet}, fmt::Debug, - sync::Arc, }; use anyhow::{anyhow, bail, Result}; use enum_map::{Enum, EnumMap}; -use erars_ast::{EventType, Interner, StrKey, Value, VariableInfo}; +use erars_ast::{EventType, Interner, StrKey, Value, VariableInfo, GLOBAL_INTERNER}; use erars_compiler::{CharacterTemplate, HeaderInfo, ReplaceInfo}; use hashbrown::HashMap; use rand::SeedableRng; @@ -58,7 +57,7 @@ pub struct SerializableGlobalVariableStorage { #[derive(Clone)] pub struct VariableStorage { - interner: Arc, + interner: &'static Interner, character_len: usize, rng: ChaCha20Rng, variables: HashMap, @@ -68,13 +67,15 @@ pub struct VariableStorage { } impl VariableStorage { - pub fn new(interner: Arc, infos: &HashMap) -> Self { + pub fn new(infos: &HashMap) -> Self { let mut variables = HashMap::new(); for (k, v) in infos { variables.insert(*k, (v.clone(), UniformVariable::new(v))); } + let interner = &*GLOBAL_INTERNER; + Self { character_len: 0, rng: ChaCha20Rng::from_entropy(), @@ -90,12 +91,8 @@ impl VariableStorage { } } - pub fn clone_interner(&self) -> Arc { - self.interner.clone() - } - #[inline] - pub fn interner(&self) -> &Interner { + pub fn interner(&self) -> &'static Interner { &self.interner } @@ -332,7 +329,7 @@ impl VariableStorage { idx: usize, palam_name: &BTreeMap, ) -> Result<()> { - let interner = self.interner.clone(); + let interner = self.interner(); let (palam, up, down) = self.get_var3( KnownVariableNames::Palam, KnownVariableNames::Up, @@ -352,7 +349,7 @@ impl VariableStorage { idx: usize, palam_name: &BTreeMap, ) -> Result<()> { - let interner = self.interner.clone(); + let interner = self.interner(); let (palam, up, down) = self.get_var3( KnownVariableNames::Palam, KnownVariableNames::Cup, @@ -393,11 +390,11 @@ impl VariableStorage { } pub fn get_result(&mut self) -> i64 { - self.read_int("RESULT", &[]).unwrap() + self.read_int(KnownVariableNames::Result, &[]).unwrap() } pub fn get_results(&mut self) -> String { - self.read_str("RESULTS", &[]).unwrap() + self.read_str(KnownVariableNames::ResultS, &[]).unwrap() } pub fn set_result(&mut self, i: i64) { From 57442832832ab428b0626c10444657a11f605e18 Mon Sep 17 00:00:00 2001 From: Riey Date: Fri, 14 Oct 2022 11:51:29 +0900 Subject: [PATCH 5/8] Fix REUSELASTLINE --- crates/erars-compiler/src/parser.rs | 1 + crates/erars-vm/src/system_func.rs | 4 +--- 2 files changed, 2 insertions(+), 3 deletions(-) diff --git a/crates/erars-compiler/src/parser.rs b/crates/erars-compiler/src/parser.rs index 5292d31e..335f0b2b 100644 --- a/crates/erars-compiler/src/parser.rs +++ b/crates/erars-compiler/src/parser.rs @@ -722,6 +722,7 @@ impl ParserContext { BuiltinCommand::Throw, vec![try_nom!(lex, self::expr::normal_form_str(self)(left)).1], ), + Token::ReuseLastLine(left) => Stmt::ReuseLastLine(self.interner.get_or_intern(left)), Token::Print((flags, PrintType::Plain, form)) => { Stmt::Print(flags, Expr::str(&self.interner, form)) } diff --git a/crates/erars-vm/src/system_func.rs b/crates/erars-vm/src/system_func.rs index 71acb682..017166f4 100644 --- a/crates/erars-vm/src/system_func.rs +++ b/crates/erars-vm/src/system_func.rs @@ -226,9 +226,7 @@ impl SystemState { *printc_count = 0; tx.new_line(); } - tx.printrc(&format!( - "{name}[{no:3}]", - )); + tx.printrc(&format!("{name}[{no:3}]",)); *printc_count += 1; } From dbfae0c149df15e73378dc3010c5d05281f4eb0f Mon Sep 17 00:00:00 2001 From: Riey Date: Fri, 14 Oct 2022 11:51:36 +0900 Subject: [PATCH 6/8] Fix parse error --- crates/erars-compiler/src/parser.rs | 80 +++--- tests/parser_test.rs | 370 ++++++++++++++-------------- 2 files changed, 227 insertions(+), 223 deletions(-) diff --git a/crates/erars-compiler/src/parser.rs b/crates/erars-compiler/src/parser.rs index 335f0b2b..f9912dcb 100644 --- a/crates/erars-compiler/src/parser.rs +++ b/crates/erars-compiler/src/parser.rs @@ -439,8 +439,8 @@ impl HeaderInfo { while let Some((n, s, price)) = self::csv::name_item_line(&interner, &mut lex)? { self.item_price.insert(n, price); - self.var_names.entry(var.clone()).or_default().insert(s.clone(), n); - self.var_name_var.entry(var.clone()).or_default().insert(n, s); + self.var_names.entry(var).or_default().insert(s, n); + self.var_name_var.entry(var).or_default().insert(n, s); } Ok(()) @@ -614,6 +614,8 @@ impl HeaderInfo { #[derive(Debug)] pub struct ParserContext { pub interner: &'static Interner, + pub locals_key: StrKey, + pub args_key: StrKey, pub header: Arc, pub local_strs: RefCell>, pub is_arg: Cell, @@ -630,8 +632,11 @@ impl Default for ParserContext { impl ParserContext { pub fn new(header: Arc, file_path: SmolStr) -> Self { + let interner = &*GLOBAL_INTERNER; Self { - interner: &*GLOBAL_INTERNER, + interner, + locals_key: interner.get_or_intern_static("LOCALS"), + args_key: interner.get_or_intern_static("ARGS"), header, file_path, local_strs: RefCell::default(), @@ -671,8 +676,7 @@ impl ParserContext { } pub fn is_str_var(&self, key: StrKey) -> bool { - if matches!(self.interner.resolve(&key), "LOCALS" | "ARGS") - || self.local_strs.borrow().contains(&key) + if key == self.locals_key || key == self.args_key || self.local_strs.borrow().contains(&key) { true } else if let Some(v) = self.header.global_variables.get(&key) { @@ -1026,15 +1030,15 @@ impl ParserContext { ) -> ParserResult> { let mut out = Vec::with_capacity(1024); - loop { - match self.next_token(lex)? { - Some(Token::At(mut left)) => loop { - self.local_strs.borrow_mut().clear(); - let mut compiler = crate::compiler::Compiler::new(); - let (label, args) = try_nom!(lex, self::expr::function_line(self)(left)).1; + match self.next_token(lex)? { + Some(Token::At(mut left)) => 'outer: loop { + self.local_strs.borrow_mut().clear(); + let mut compiler = crate::compiler::Compiler::new(); + let (label, args) = try_nom!(lex, self::expr::function_line(self)(left)).1; - let mut infos = Vec::new(); + let mut infos = Vec::new(); + 'inner: loop { match self.next_token(lex)? { Some(Token::At(new_left)) => { left = new_left; @@ -1044,13 +1048,13 @@ impl ParserContext { name: self.interner.get_or_intern(label), args, file_path: self.file_path.clone(), - infos: Vec::new(), + infos, }, goto_labels: compiler.goto_labels, body: compiler.out.into_boxed_slice(), }); - continue; + break 'inner; } None => { out.push(CompiledFunction { @@ -1058,13 +1062,13 @@ impl ParserContext { name: self.interner.get_or_intern(label), args, file_path: self.file_path.clone(), - infos: Vec::new(), + infos, }, goto_labels: compiler.goto_labels, body: compiler.out.into_boxed_slice(), }); - break; + break 'outer; } Some(Token::Function) => { infos.push(FunctionInfo::Function); @@ -1087,7 +1091,7 @@ impl ParserContext { } Some(Token::DimS(left)) => { let var = try_nom!(lex, self::expr::dim_line(self, true)(left)).1; - self.local_strs.borrow_mut().insert(var.var.clone()); + self.local_strs.borrow_mut().insert(var.var); infos.push(FunctionInfo::Dim(var)); } Some(Token::LocalSize(size)) => { @@ -1118,10 +1122,10 @@ impl ParserContext { } }, } - }, - Some(_) => error!(lex, "함수는 @로 시작해야 합니다."), - None => break, - } + } + }, + Some(_) => error!(lex, "함수는 @로 시작해야 합니다."), + None => {} } Ok(out) @@ -1130,15 +1134,15 @@ impl ParserContext { pub fn parse<'s>(&self, lex: &mut Lexer<'s, Token<'s>>) -> ParserResult> { let mut out = Vec::new(); - loop { - match self.next_token(lex)? { - Some(Token::At(mut left)) => loop { - self.local_strs.borrow_mut().clear(); - let mut body = Vec::new(); - let (label, args) = try_nom!(lex, self::expr::function_line(self)(left)).1; + match self.next_token(lex)? { + Some(Token::At(mut left)) => 'outer: loop { + self.local_strs.borrow_mut().clear(); + let mut body = Vec::new(); + let (label, args) = try_nom!(lex, self::expr::function_line(self)(left)).1; - let mut infos = Vec::new(); + let mut infos = Vec::new(); + 'inner: loop { match self.next_token(lex)? { Some(Token::At(new_left)) => { left = new_left; @@ -1148,12 +1152,12 @@ impl ParserContext { name: self.interner.get_or_intern(label), args, file_path: self.file_path.clone(), - infos: Vec::new(), + infos, }, - body: std::mem::take(&mut body), + body, }); - continue; + break 'inner; } None => { out.push(Function { @@ -1161,12 +1165,12 @@ impl ParserContext { name: self.interner.get_or_intern(label), args, file_path: self.file_path.clone(), - infos: Vec::new(), + infos, }, body, }); - break; + break 'outer; } Some(Token::Function) => { infos.push(FunctionInfo::Function); @@ -1189,7 +1193,7 @@ impl ParserContext { } Some(Token::DimS(left)) => { let var = try_nom!(lex, self::expr::dim_line(self, true)(left)).1; - self.local_strs.borrow_mut().insert(var.var.clone()); + self.local_strs.borrow_mut().insert(var.var); infos.push(FunctionInfo::Dim(var)); } Some(Token::LocalSize(size)) => { @@ -1217,10 +1221,10 @@ impl ParserContext { } }, } - }, - Some(_) => error!(lex, "함수는 @로 시작해야 합니다."), - None => break, - } + } + }, + Some(_) => error!(lex, "함수는 @로 시작해야 합니다."), + None => {} } Ok(out) diff --git a/tests/parser_test.rs b/tests/parser_test.rs index 466201d7..eeb03ba2 100644 --- a/tests/parser_test.rs +++ b/tests/parser_test.rs @@ -10,7 +10,7 @@ mod body { r#"tests/parse_tests/bodys/alignment.erb"#, ParserContext::parse_body_str ), - r#" + " [ StmtWithPos( Alignment( @@ -40,7 +40,7 @@ mod body { Print( NEWLINE, FormText( - {Var(Variable { var: "LOCALS", func_extern: None, args: [] })}, + {Var(Variable { var: LOCALS, func_extern: None, args: [] })}, ), ), ScriptPosition { @@ -51,7 +51,7 @@ mod body { Print( NEWLINE, FormText( - {Var(Variable { var: "LOCALS", func_extern: None, args: [] })}, + {Var(Variable { var: LOCALS, func_extern: None, args: [] })}, ), ), ScriptPosition { @@ -59,7 +59,7 @@ mod body { }, ), ] -"# +" ); } @@ -70,12 +70,12 @@ mod body { r#"tests/parse_tests/bodys/assign.erb"#, ParserContext::parse_body_str ), - r#" + " [ StmtWithPos( Assign( Variable { - var: "COUNT", + var: COUNT, func_extern: None, args: [ BinopExpr( @@ -105,7 +105,7 @@ mod body { }, ), ] -"# +" ); } @@ -116,12 +116,12 @@ mod body { r#"tests/parse_tests/bodys/assign_add.erb"#, ParserContext::parse_body_str ), - r#" + " [ StmtWithPos( Assign( Variable { - var: "FLAG", + var: FLAG, func_extern: None, args: [ Int( @@ -141,7 +141,7 @@ mod body { }, ), ] -"# +" ); } @@ -152,12 +152,12 @@ mod body { r#"tests/parse_tests/bodys/assign_str.erb"#, ParserContext::parse_body_str ), - r#" + " [ StmtWithPos( Assign( Variable { - var: "LOCALS", + var: LOCALS, func_extern: None, args: [], }, @@ -173,13 +173,13 @@ mod body { StmtWithPos( Assign( Variable { - var: "LOCALS", + var: LOCALS, func_extern: None, args: [], }, None, FormText( - {Var(Variable { var: "LOCAL", func_extern: None, args: [Int(0)] })}.{BuiltinMethod(ToStr, [Var(Variable { var: "LOCAL", func_extern: None, args: [Int(1)] }), String("00")])}, + {Var(Variable { var: LOCAL, func_extern: None, args: [Int(0)] })}.{BuiltinMethod(ToStr, [Var(Variable { var: LOCAL, func_extern: None, args: [Int(1)] }), String(00)])}, ), ), ScriptPosition { @@ -189,7 +189,7 @@ mod body { StmtWithPos( Assign( Variable { - var: "LOCALS", + var: LOCALS, func_extern: None, args: [], }, @@ -205,12 +205,12 @@ mod body { StmtWithPos( Assign( Variable { - var: "NICKNAME", + var: NICKNAME, func_extern: None, args: [ Var( Variable { - var: "MASTER", + var: MASTER, func_extern: None, args: [], }, @@ -219,7 +219,7 @@ mod body { }, None, FormText( - {CondExpr(Var(Variable { var: "TALENT", func_extern: None, args: [Var(Variable { var: "MASTER", func_extern: None, args: [] }), Int(120)] }), FormText(신사), FormText(숙녀))}, + {CondExpr(Var(Variable { var: TALENT, func_extern: None, args: [Var(Variable { var: MASTER, func_extern: None, args: [] }), Int(120)] }), FormText(신사), FormText(숙녀))}, ), ), ScriptPosition { @@ -229,7 +229,7 @@ mod body { StmtWithPos( Assign( Variable { - var: "LOCALS", + var: LOCALS, func_extern: None, args: [], }, @@ -243,7 +243,7 @@ mod body { }, ), ] -"# +" ); } @@ -254,12 +254,12 @@ mod body { r#"tests/parse_tests/bodys/call.erb"#, ParserContext::parse_body_str ), - r#" + " [ StmtWithPos( Call { name: String( - "FOO", + FOO, ), args: [ Int( @@ -267,7 +267,7 @@ mod body { ), Var( Variable { - var: "A", + var: A, func_extern: None, args: [ Int( @@ -277,7 +277,7 @@ mod body { }, ), String( - "123", + 123, ), ], is_jump: false, @@ -290,7 +290,7 @@ mod body { }, ), ] -"# +" ); } @@ -301,14 +301,14 @@ mod body { r#"tests/parse_tests/bodys/command.erb"#, ParserContext::parse_body_str ), - r#" + " [ StmtWithPos( Command( CustomDrawLine, [ String( - "=", + =, ), ], ), @@ -317,7 +317,7 @@ mod body { }, ), ] -"# +" ); } @@ -328,12 +328,12 @@ mod body { r#"tests/parse_tests/bodys/for.erb"#, ParserContext::parse_body_str ), - r#" + " [ StmtWithPos( For( Variable { - var: "COUNT", + var: COUNT, func_extern: None, args: [], }, @@ -355,7 +355,7 @@ mod body { [ Var( Variable { - var: "COUNT", + var: COUNT, func_extern: None, args: [], }, @@ -373,7 +373,7 @@ mod body { }, ), ] -"# +" ); } @@ -384,13 +384,13 @@ mod body { r#"tests/parse_tests/bodys/hello.erb"#, ParserContext::parse_body_str ), - r#" + " [ StmtWithPos( Print( NEWLINE, String( - "Hello, world!", + Hello, world!, ), ), ScriptPosition { @@ -398,7 +398,7 @@ mod body { }, ), ] -"# +" ); } @@ -409,7 +409,7 @@ mod body { r#"tests/parse_tests/bodys/if.erb"#, ParserContext::parse_body_str ), - r#" + " [ StmtWithPos( If( @@ -418,7 +418,7 @@ mod body { BinopExpr( Var( Variable { - var: "A", + var: A, func_extern: None, args: [], }, @@ -433,7 +433,7 @@ mod body { Print( (empty), String( - "A > 1", + A > 1, ), ), ScriptPosition { @@ -446,7 +446,7 @@ mod body { BinopExpr( Var( Variable { - var: "A", + var: A, func_extern: None, args: [], }, @@ -461,7 +461,7 @@ mod body { Print( (empty), String( - "A == 1", + A == 1, ), ), ScriptPosition { @@ -476,7 +476,7 @@ mod body { Print( (empty), String( - "A < 1", + A < 1, ), ), ScriptPosition { @@ -490,7 +490,7 @@ mod body { }, ), ] -"# +" ); } @@ -501,12 +501,12 @@ mod body { r#"tests/parse_tests/bodys/number.erb"#, ParserContext::parse_body_str ), - r#" + " [ StmtWithPos( Assign( Variable { - var: "LOCAL", + var: LOCAL, func_extern: None, args: [], }, @@ -522,7 +522,7 @@ mod body { StmtWithPos( Assign( Variable { - var: "LOCAL", + var: LOCAL, func_extern: None, args: [], }, @@ -538,7 +538,7 @@ mod body { StmtWithPos( Assign( Variable { - var: "LOCAL", + var: LOCAL, func_extern: None, args: [], }, @@ -554,7 +554,7 @@ mod body { StmtWithPos( Assign( Variable { - var: "LOCAL", + var: LOCAL, func_extern: None, args: [], }, @@ -570,7 +570,7 @@ mod body { StmtWithPos( Assign( Variable { - var: "LOCAL", + var: LOCAL, func_extern: None, args: [], }, @@ -586,7 +586,7 @@ mod body { StmtWithPos( Assign( Variable { - var: "LOCAL", + var: LOCAL, func_extern: None, args: [], }, @@ -605,7 +605,7 @@ mod body { StmtWithPos( Assign( Variable { - var: "LOCAL", + var: LOCAL, func_extern: None, args: [], }, @@ -624,7 +624,7 @@ mod body { StmtWithPos( Assign( Variable { - var: "LOCAL", + var: LOCAL, func_extern: None, args: [], }, @@ -641,7 +641,7 @@ mod body { }, ), ] -"# +" ); } @@ -652,7 +652,7 @@ mod body { r#"tests/parse_tests/bodys/print_data.erb"#, ParserContext::parse_body_str ), - r#" + " [ StmtWithPos( PrintData( @@ -661,20 +661,20 @@ mod body { [ [ String( - "data", + data, ), ], [ FormText( - LOCAL={Var(Variable { var: "LOCAL", func_extern: None, args: [] })}, + LOCAL={Var(Variable { var: LOCAL, func_extern: None, args: [] })}, ), ], [ String( - "list", + list, ), String( - "form", + form, ), ], ], @@ -684,7 +684,7 @@ mod body { }, ), ] -"# +" ); } @@ -695,7 +695,7 @@ mod body { r#"tests/parse_tests/bodys/print_simple.erb"#, ParserContext::parse_body_str ), - r#" + " [ StmtWithPos( Print( @@ -712,7 +712,7 @@ mod body { Print( NEWLINE | WAIT, FormText( - {Method("조사처리", [Var(Variable { var: "CALLNAME", func_extern: None, args: [Method("GET_CHARA_M", [])] }), String("와")])} 같이 온 걸 보니, 단단히 각오하고 온 것 같다, + {Method(조사처리, [Var(Variable { var: CALLNAME, func_extern: None, args: [Method(GET_CHARA_M, [])] }), String(와)])} 같이 온 걸 보니, 단단히 각오하고 온 것 같다, ), ), ScriptPosition { @@ -723,7 +723,7 @@ mod body { Print( NEWLINE, FormText( - {Var(Variable { var: "CALLNAME", func_extern: None, args: [Var(Variable { var: "ARG", func_extern: None, args: [] })] })}의 교습 관찰 결과 완료 결과:임시 성과치 {Var(Variable { var: "LOCAL", func_extern: None, args: [Int(0)] })}에 의한 실제 성과치 {Var(Variable { var: "LOCAL", func_extern: None, args: [Int(2)] })} 증가⇒{CondExpr(BinopExpr(Var(Variable { var: "LOCAL", func_extern: None, args: [Int(1)] }), Equal, Int(1)), FormText(성공), FormText(실패))}({Var(Variable { var: "CFLAG", func_extern: None, args: [Var(Variable { var: "ARG", func_extern: None, args: [] }), Int(693)] })}%) 작업 내용:{Var(Variable { var: "CFLAG", func_extern: None, args: [Var(Variable { var: "ARG", func_extern: None, args: [] }), Int(690)] })}, + {Var(Variable { var: CALLNAME, func_extern: None, args: [Var(Variable { var: ARG, func_extern: None, args: [] })] })}의 교습 관찰 결과 완료 결과:임시 성과치 {Var(Variable { var: LOCAL, func_extern: None, args: [Int(0)] })}에 의한 실제 성과치 {Var(Variable { var: LOCAL, func_extern: None, args: [Int(2)] })} 증가⇒{CondExpr(BinopExpr(Var(Variable { var: LOCAL, func_extern: None, args: [Int(1)] }), Equal, Int(1)), FormText(성공), FormText(실패))}({Var(Variable { var: CFLAG, func_extern: None, args: [Var(Variable { var: ARG, func_extern: None, args: [] }), Int(693)] })}%) 작업 내용:{Var(Variable { var: CFLAG, func_extern: None, args: [Var(Variable { var: ARG, func_extern: None, args: [] }), Int(690)] })}, ), ), ScriptPosition { @@ -734,7 +734,7 @@ mod body { Print( NEWLINE | WAIT, FormText( - 보지에서 애액을 흘렸{CondExpr(BinopExpr(Var(Variable { var: "TEQUIP", func_extern: None, args: [Int(42)] }), Equal, Int(0)), FormText(고, 작은 한숨을 토해냈), String(""))}다., + 보지에서 애액을 흘렸{CondExpr(BinopExpr(Var(Variable { var: TEQUIP, func_extern: None, args: [Int(42)] }), Equal, Int(0)), FormText(고, 작은 한숨을 토해냈), String())}다., ), ), ScriptPosition { @@ -742,7 +742,7 @@ mod body { }, ), ] -"# +" ); } @@ -753,13 +753,13 @@ mod body { r#"tests/parse_tests/bodys/printc.erb"#, ParserContext::parse_body_str ), - r#" + " [ StmtWithPos( Print( LEFT_ALIGN, String( - "LC", + LC, ), ), ScriptPosition { @@ -770,7 +770,7 @@ mod body { Print( RIGHT_ALIGN, String( - "C", + C, ), ), ScriptPosition { @@ -778,7 +778,7 @@ mod body { }, ), ] -"# +" ); } @@ -789,7 +789,7 @@ mod body { r#"tests/parse_tests/bodys/repeat.erb"#, ParserContext::parse_body_str ), - r#" + " [ StmtWithPos( Repeat( @@ -801,12 +801,12 @@ mod body { StmtWithPos( Assign( Variable { - var: "MARK", + var: MARK, func_extern: None, args: [ Var( Variable { - var: "COUNT", + var: COUNT, func_extern: None, args: [], }, @@ -830,7 +830,7 @@ mod body { BinopExpr( Var( Variable { - var: "COUNT", + var: COUNT, func_extern: None, args: [], }, @@ -838,7 +838,7 @@ mod body { Equal, Var( Variable { - var: "MASTER", + var: MASTER, func_extern: None, args: [], }, @@ -860,12 +860,12 @@ mod body { BinopExpr( Var( Variable { - var: "CFLAG", + var: CFLAG, func_extern: None, args: [ Var( Variable { - var: "COUNT", + var: COUNT, func_extern: None, args: [], }, @@ -899,7 +899,7 @@ mod body { }, ), ] -"# +" ); } @@ -910,7 +910,7 @@ mod body { r#"tests/parse_tests/bodys/selectcase.erb"#, ParserContext::parse_body_str ), - r#" + " [ StmtWithPos( SelectCase( @@ -931,7 +931,7 @@ mod body { Print( (empty), String( - "FOO", + FOO, ), ), ScriptPosition { @@ -956,7 +956,7 @@ mod body { Print( (empty), String( - "BAR", + BAR, ), ), ScriptPosition { @@ -972,7 +972,7 @@ mod body { Print( (empty), String( - "BAZ", + BAZ, ), ), ScriptPosition { @@ -987,7 +987,7 @@ mod body { }, ), ] -"# +" ); } @@ -998,7 +998,7 @@ mod body { r#"tests/parse_tests/bodys/sif.erb"#, ParserContext::parse_body_str ), - r#" + " [ StmtWithPos( Sif( @@ -1009,7 +1009,7 @@ mod body { Print( (empty), String( - "45", + 45, ), ), ScriptPosition { @@ -1026,21 +1026,21 @@ mod body { BinopExpr( Var( Variable { - var: "LOCALS", + var: LOCALS, func_extern: None, args: [], }, ), NotEqual, String( - "", + , ), ), StmtWithPos( Print( NEWLINE, FormText( - {Var(Variable { var: "LOCALS", func_extern: None, args: [] })}, + {Var(Variable { var: LOCALS, func_extern: None, args: [] })}, ), ), ScriptPosition { @@ -1056,7 +1056,7 @@ mod body { Print( (empty), String( - "32", + 32, ), ), ScriptPosition { @@ -1064,7 +1064,7 @@ mod body { }, ), ] -"# +" ); } @@ -1075,12 +1075,12 @@ mod body { r#"tests/parse_tests/bodys/times.erb"#, ParserContext::parse_body_str ), - r#" + " [ StmtWithPos( Times( Variable { - var: "LOCAL", + var: LOCAL, func_extern: None, args: [], }, @@ -1093,7 +1093,7 @@ mod body { }, ), ] -"# +" ); } @@ -1104,12 +1104,12 @@ mod body { r#"tests/parse_tests/bodys/trailing_comma.erb"#, ParserContext::parse_body_str ), - r#" + " [ StmtWithPos( Call { name: String( - "CALLFUNC", + CALLFUNC, ), args: [ Int( @@ -1129,7 +1129,7 @@ mod body { }, ), ] -"# +" ); } } @@ -1144,12 +1144,12 @@ mod expr { r#"tests/parse_tests/exprs/boolean.erb"#, ParserContext::parse_expr_str ), - r#" + " BinopExpr( BinopExpr( Var( Variable { - var: "RESULT", + var: RESULT, func_extern: None, args: [], }, @@ -1163,12 +1163,12 @@ BinopExpr( BinopExpr( Var( Variable { - var: "TALENT", + var: TALENT, func_extern: None, args: [ Var( Variable { - var: "MASTER", + var: MASTER, func_extern: None, args: [], }, @@ -1185,7 +1185,7 @@ BinopExpr( ), ), ) -"# +" ); } @@ -1196,7 +1196,7 @@ BinopExpr( r#"tests/parse_tests/exprs/complex_op.erb"#, ParserContext::parse_expr_str ), - r#" + " BinopExpr( BinopExpr( Int( @@ -1210,12 +1210,12 @@ BinopExpr( Sub, Var( Variable { - var: "ABL", + var: ABL, func_extern: None, args: [ Var( Variable { - var: "ARG", + var: ARG, func_extern: None, args: [], }, @@ -1244,7 +1244,7 @@ BinopExpr( ), ), ) -"# +" ); } @@ -1278,10 +1278,10 @@ CondExpr( r#"tests/parse_tests/exprs/csv.erb"#, ParserContext::parse_expr_str ), - r#" + " Var( Variable { - var: "FLAG", + var: FLAG, func_extern: None, args: [ Int( @@ -1290,7 +1290,7 @@ Var( ], }, ) -"# +" ); } @@ -1301,19 +1301,19 @@ Var( r#"tests/parse_tests/exprs/method.erb"#, ParserContext::parse_expr_str ), - r#" + " Method( - "FOO", + FOO, [ Int( 123, ), String( - "BAR", + BAR, ), Var( Variable { - var: "LOCAL", + var: LOCAL, func_extern: None, args: [ Int( @@ -1324,7 +1324,7 @@ Method( ), ], ) -"# +" ); } @@ -1410,11 +1410,11 @@ BinopExpr( r#"tests/parse_tests/exprs/str_literal.erb"#, ParserContext::parse_expr_str ), - r#" + " String( - "", + , ) -"# +" ); } @@ -1425,9 +1425,9 @@ String( r#"tests/parse_tests/exprs/trailing_comma.erb"#, ParserContext::parse_expr_str ), - r#" + " Method( - "METHOD", + METHOD, [ Int( 1, @@ -1437,7 +1437,7 @@ Method( ), ], ) -"# +" ); } @@ -1448,10 +1448,10 @@ Method( r#"tests/parse_tests/exprs/var_arg.erb"#, ParserContext::parse_expr_str ), - r#" + " Var( Variable { - var: "COUNT", + var: COUNT, func_extern: None, args: [ Int( @@ -1460,7 +1460,7 @@ Var( ], }, ) -"# +" ); } @@ -1471,15 +1471,15 @@ Var( r#"tests/parse_tests/exprs/var_complex.erb"#, ParserContext::parse_expr_str ), - r#" + " Var( Variable { - var: "COUNT", + var: COUNT, func_extern: None, args: [ Var( Variable { - var: "A", + var: A, func_extern: None, args: [ Int( @@ -1494,7 +1494,7 @@ Var( ], }, ) -"# +" ); } @@ -1505,15 +1505,15 @@ Var( r#"tests/parse_tests/exprs/var_empty.erb"#, ParserContext::parse_expr_str ), - r#" + " Var( Variable { - var: "COUNT", + var: COUNT, func_extern: None, args: [], }, ) -"# +" ); } } @@ -1532,7 +1532,7 @@ mod function { Function { header: FunctionHeader { file_path: "tests/parse_tests/functions/call.erb", - name: "FOO", + name: FOO, args: [], infos: [], }, @@ -1540,7 +1540,7 @@ Function { StmtWithPos( Assign( Variable { - var: "LOCALS", + var: LOCALS, func_extern: None, args: [], }, @@ -1556,7 +1556,7 @@ Function { StmtWithPos( Goto { label: String( - "LABEL", + LABEL, ), catch_body: None, }, @@ -1567,7 +1567,7 @@ Function { StmtWithPos( Goto { label: FormText( - {Var(Variable { var: "LOCALS", func_extern: None, args: [] })}, + {Var(Variable { var: LOCALS, func_extern: None, args: [] })}, ), catch_body: None, }, @@ -1578,7 +1578,7 @@ Function { StmtWithPos( Goto { label: FormText( - {Var(Variable { var: "LOCALS", func_extern: None, args: [] })}, + {Var(Variable { var: LOCALS, func_extern: None, args: [] })}, ), catch_body: Some( [], @@ -1591,7 +1591,7 @@ Function { StmtWithPos( Goto { label: FormText( - {Var(Variable { var: "LOCALS", func_extern: None, args: [] })}, + {Var(Variable { var: LOCALS, func_extern: None, args: [] })}, ), catch_body: Some( [ @@ -1599,7 +1599,7 @@ Function { Print( NEWLINE, String( - "CATCH", + CATCH, ), ), ScriptPosition { @@ -1616,7 +1616,7 @@ Function { StmtWithPos( Call { name: String( - "BAR", + BAR, ), args: [], is_jump: false, @@ -1631,7 +1631,7 @@ Function { StmtWithPos( Call { name: String( - "BAR", + BAR, ), args: [], is_jump: false, @@ -1648,7 +1648,7 @@ Function { StmtWithPos( Call { name: String( - "BAR", + BAR, ), args: [], is_jump: false, @@ -1665,7 +1665,7 @@ Function { StmtWithPos( Call { name: String( - "BAR", + BAR, ), args: [], is_jump: true, @@ -1680,7 +1680,7 @@ Function { StmtWithPos( Call { name: String( - "BAR", + BAR, ), args: [], is_jump: true, @@ -1714,7 +1714,7 @@ Function { StmtWithPos( Call { name: String( - "BAZ", + BAZ, ), args: [ CondExpr( @@ -1740,7 +1740,7 @@ Function { ), StmtWithPos( Label( - "LABEL", + LABEL, ), ScriptPosition { line: 25, @@ -1763,12 +1763,12 @@ Function { Function { header: FunctionHeader { file_path: "tests/parse_tests/functions/dim.erb", - name: "SYSTEM_TITLE", + name: SYSTEM_TITLE, args: [], infos: [ Dim( LocalVariable { - var: "FOO", + var: FOO, info: VariableInfo { is_chara: false, is_str: false, @@ -1793,7 +1793,7 @@ Function { [ Var( Variable { - var: "FOO", + var: FOO, func_extern: None, args: [], }, @@ -1821,7 +1821,7 @@ Function { Function { header: FunctionHeader { file_path: "tests/parse_tests/functions/function.erb", - name: "FOO", + name: FOO, args: [], infos: [ EventFlag( @@ -1834,7 +1834,7 @@ Function { Print( NEWLINE, String( - "Hello", + Hello, ), ), ScriptPosition { @@ -1869,11 +1869,11 @@ Function { Function { header: FunctionHeader { file_path: "tests/parse_tests/functions/juel.erb", - name: "COMMON_MOVE_JUEL", + name: COMMON_MOVE_JUEL, args: [ ( Variable { - var: "ARG", + var: ARG, func_extern: None, args: [], }, @@ -1881,7 +1881,7 @@ Function { ), ( Variable { - var: "ARG", + var: ARG, func_extern: None, args: [ Int( @@ -1893,7 +1893,7 @@ Function { ), ( Variable { - var: "ARG", + var: ARG, func_extern: None, args: [ Int( @@ -1905,7 +1905,7 @@ Function { ), ( Variable { - var: "ARG", + var: ARG, func_extern: None, args: [ Int( @@ -1917,7 +1917,7 @@ Function { ), ( Variable { - var: "ARG", + var: ARG, func_extern: None, args: [ Int( @@ -1934,7 +1934,7 @@ Function { StmtWithPos( Assign( Variable { - var: "LOCAL", + var: LOCAL, func_extern: None, args: [ Int( @@ -1949,19 +1949,19 @@ Function { BinopExpr( Var( Variable { - var: "JUEL", + var: JUEL, func_extern: None, args: [ Var( Variable { - var: "ARG", + var: ARG, func_extern: None, args: [], }, ), Var( Variable { - var: "ARG", + var: ARG, func_extern: None, args: [ Int( @@ -1976,7 +1976,7 @@ Function { Add, Var( Variable { - var: "ARG", + var: ARG, func_extern: None, args: [ Int( @@ -2011,7 +2011,7 @@ Function { StmtWithPos( Assign( Variable { - var: "LOCAL", + var: LOCAL, func_extern: None, args: [ Int( @@ -2023,7 +2023,7 @@ Function { BinopExpr( Var( Variable { - var: "LOCAL", + var: LOCAL, func_extern: None, args: [ Int( @@ -2035,19 +2035,19 @@ Function { Sub, Var( Variable { - var: "JUEL", + var: JUEL, func_extern: None, args: [ Var( Variable { - var: "ARG", + var: ARG, func_extern: None, args: [], }, ), Var( Variable { - var: "ARG", + var: ARG, func_extern: None, args: [ Int( @@ -2068,13 +2068,13 @@ Function { StmtWithPos( Assign( Variable { - var: "LOCALS", + var: LOCALS, func_extern: None, args: [], }, None, FormText( - {BuiltinVar(PalamName, [Var(Variable { var: "ARG", func_extern: None, args: [Int(1)] })])}의 구슬{CondExpr(BinopExpr(BinopExpr(Var(Variable { var: "ARG", func_extern: None, args: [Int(4)] }), Sub, BinopExpr(Var(Variable { var: "ARG", func_extern: None, args: [] }), NotEqual, Var(Variable { var: "TARGET", func_extern: None, args: [] }))), LessOrEqual, Int(0)), FormText(({Var(Variable { var: "CALLNAME", func_extern: None, args: [Var(Variable { var: "ARG", func_extern: None, args: [] })] })})), FormText())} {CondExpr(BinopExpr(BuiltinMethod(Sign, [Var(Variable { var: "LOCAL", func_extern: None, args: [Int(2)] })]), Equal, Int(1)), FormText(+), FormText(-))} {BuiltinMethod(Abs, [Var(Variable { var: "LOCAL", func_extern: None, args: [Int(2)] })])}, + {BuiltinVar(PalamName, [Var(Variable { var: ARG, func_extern: None, args: [Int(1)] })])}의 구슬{CondExpr(BinopExpr(BinopExpr(Var(Variable { var: ARG, func_extern: None, args: [Int(4)] }), Sub, BinopExpr(Var(Variable { var: ARG, func_extern: None, args: [] }), NotEqual, Var(Variable { var: TARGET, func_extern: None, args: [] }))), LessOrEqual, Int(0)), FormText(({Var(Variable { var: CALLNAME, func_extern: None, args: [Var(Variable { var: ARG, func_extern: None, args: [] })] })})), FormText())} {CondExpr(BinopExpr(BuiltinMethod(Sign, [Var(Variable { var: LOCAL, func_extern: None, args: [Int(2)] })]), Equal, Int(1)), FormText(+), FormText(-))} {BuiltinMethod(Abs, [Var(Variable { var: LOCAL, func_extern: None, args: [Int(2)] })])}, ), ), ScriptPosition { @@ -2084,19 +2084,19 @@ Function { StmtWithPos( Assign( Variable { - var: "JUEL", + var: JUEL, func_extern: None, args: [ Var( Variable { - var: "ARG", + var: ARG, func_extern: None, args: [], }, ), Var( Variable { - var: "ARG", + var: ARG, func_extern: None, args: [ Int( @@ -2110,7 +2110,7 @@ Function { None, Var( Variable { - var: "LOCAL", + var: LOCAL, func_extern: None, args: [ Int( @@ -2134,7 +2134,7 @@ Function { [ Var( Variable { - var: "LOCAL", + var: LOCAL, func_extern: None, args: [ Int( @@ -2155,7 +2155,7 @@ Function { SelectCase( Var( Variable { - var: "ARG", + var: ARG, func_extern: None, args: [ Int( @@ -2179,7 +2179,7 @@ Function { NEWLINE, Var( Variable { - var: "LOCALS", + var: LOCALS, func_extern: None, args: [], }, @@ -2218,7 +2218,7 @@ Function { NEWLINE | WAIT, Var( Variable { - var: "LOCALS", + var: LOCALS, func_extern: None, args: [], }, @@ -2297,7 +2297,7 @@ mod program { Function { header: FunctionHeader { file_path: "tests/parse_tests/programs/call_form.erb", - name: "SYSTEM_TITLE", + name: SYSTEM_TITLE, args: [], infos: [], }, @@ -2326,11 +2326,11 @@ mod program { Function { header: FunctionHeader { file_path: "tests/parse_tests/programs/call_form.erb", - name: "FOO_123", + name: FOO_123, args: [ ( Variable { - var: "ARG", + var: ARG, func_extern: None, args: [], }, @@ -2344,7 +2344,7 @@ mod program { Print( (empty), FormText( - FOO_{Var(Variable { var: "ARG", func_extern: None, args: [] })}, + FOO_{Var(Variable { var: ARG, func_extern: None, args: [] })}, ), ), ScriptPosition { @@ -2370,7 +2370,7 @@ mod program { Function { header: FunctionHeader { file_path: "tests/parse_tests/programs/method_call.erb", - name: "FOO", + name: FOO, args: [], infos: [], }, @@ -2378,13 +2378,13 @@ mod program { StmtWithPos( Assign( Variable { - var: "A", + var: A, func_extern: None, args: [], }, None, Method( - "BAR", + BAR, [], ), ), @@ -2397,7 +2397,7 @@ mod program { Function { header: FunctionHeader { file_path: "tests/parse_tests/programs/method_call.erb", - name: "BAR", + name: BAR, args: [], infos: [ Function, @@ -2436,7 +2436,7 @@ mod program { Function { header: FunctionHeader { file_path: "tests/parse_tests/programs/simple.erb", - name: "FOO", + name: FOO, args: [], infos: [], }, @@ -2445,7 +2445,7 @@ mod program { Print( (empty), String( - "foo", + foo, ), ), ScriptPosition { @@ -2457,7 +2457,7 @@ mod program { Function { header: FunctionHeader { file_path: "tests/parse_tests/programs/simple.erb", - name: "FOO", + name: FOO, args: [], infos: [], }, @@ -2466,7 +2466,7 @@ mod program { Print( (empty), String( - "foo", + foo, ), ), ScriptPosition { @@ -2478,7 +2478,7 @@ mod program { Function { header: FunctionHeader { file_path: "tests/parse_tests/programs/simple.erb", - name: "BAR", + name: BAR, args: [], infos: [], }, @@ -2487,7 +2487,7 @@ mod program { Print( (empty), String( - "bar", + bar, ), ), ScriptPosition { From fd4243cc6d5eca209d69be58ebf9962db0671dab Mon Sep 17 00:00:00 2001 From: Riey Date: Fri, 14 Oct 2022 11:57:16 +0900 Subject: [PATCH 7/8] Fix frontend --- crates/erars-http/src/http_frontend.rs | 8 ++++++-- crates/erars-http/src/main.rs | 4 ++-- crates/erars-loader/src/lib.rs | 5 +++-- crates/erars-stdio/src/main.rs | 4 ++-- crates/erars-stdio/src/stdio_frontend.rs | 6 ++---- 5 files changed, 15 insertions(+), 12 deletions(-) diff --git a/crates/erars-http/src/http_frontend.rs b/crates/erars-http/src/http_frontend.rs index 3334d601..3f4f4830 100644 --- a/crates/erars-http/src/http_frontend.rs +++ b/crates/erars-http/src/http_frontend.rs @@ -135,13 +135,17 @@ async fn start( } impl HttpFrontend { - pub fn run(&mut self, vm: TerminalVm, mut ctx: VmContext) -> anyhow::Result<()> { + pub fn run( + &mut self, + vm: TerminalVm, + mut ctx: VmContext, + mut vconsole: VirtualConsole, + ) -> anyhow::Result<()> { let rt = tokio::runtime::Builder::new_multi_thread().enable_all().build()?; let _guard = rt.enter(); let (input_tx, input_rx) = bounded(8); - let mut vconsole = VirtualConsole::new(ctx.config.printc_width); let vconsole_buf = Arc::new(RwLock::new(( VirtualConsole::new(ctx.config.printc_width), None, diff --git a/crates/erars-http/src/main.rs b/crates/erars-http/src/main.rs index bc2da967..3fb7833b 100644 --- a/crates/erars-http/src/main.rs +++ b/crates/erars-http/src/main.rs @@ -64,8 +64,8 @@ fn main() { None => Vec::new(), }; - let (vm, ctx) = run_script(args.target_path, inputs).unwrap(); + let (vm, ctx, vconsole) = run_script(args.target_path, inputs).unwrap(); let mut frontend = http_frontend::HttpFrontend::new(args.port); - frontend.run(vm, ctx).unwrap(); + frontend.run(vm, ctx, vconsole).unwrap(); } diff --git a/crates/erars-loader/src/lib.rs b/crates/erars-loader/src/lib.rs index 74c3c649..06d51776 100644 --- a/crates/erars-loader/src/lib.rs +++ b/crates/erars-loader/src/lib.rs @@ -78,7 +78,7 @@ fn read_file(path: &Path) -> std::io::Result { pub fn run_script( target_path: String, inputs: Vec, -) -> anyhow::Result<(TerminalVm, VmContext)> { +) -> anyhow::Result<(TerminalVm, VmContext, VirtualConsole)> { let mut time = Instant::now(); let config_path = format!("{target_path}/emuera.config"); @@ -106,6 +106,7 @@ pub fn run_script( time = Instant::now(); tx.print_line(format!("[{}]: {}ms", $work, m)); + log::info!("[{}]: {}ms", $work, m); }; } @@ -351,5 +352,5 @@ pub fn run_script( let vm = TerminalVm::new(function_dic, target_path.into()); - Ok((vm, ctx)) + Ok((vm, ctx, tx)) } diff --git a/crates/erars-stdio/src/main.rs b/crates/erars-stdio/src/main.rs index d9a74fcc..7f59ba8f 100644 --- a/crates/erars-stdio/src/main.rs +++ b/crates/erars-stdio/src/main.rs @@ -66,8 +66,8 @@ fn main() { None => Vec::new(), }; - let (vm, mut ctx) = run_script(args.target_path, inputs).unwrap(); + let (vm, mut ctx, tx) = run_script(args.target_path, inputs).unwrap(); - let mut frontend = stdio_frontend::StdioFrontend::new(ctx.config.printc_width); + let mut frontend = stdio_frontend::StdioFrontend::new(tx); frontend.run(&vm, &mut ctx).unwrap(); } diff --git a/crates/erars-stdio/src/stdio_frontend.rs b/crates/erars-stdio/src/stdio_frontend.rs index aa58fc14..131c655c 100644 --- a/crates/erars-stdio/src/stdio_frontend.rs +++ b/crates/erars-stdio/src/stdio_frontend.rs @@ -7,10 +7,8 @@ pub struct StdioFrontend { } impl StdioFrontend { - pub fn new(printc_width: usize) -> Self { - Self { - vconsole: VirtualConsole::new(printc_width), - } + pub fn new(vconsole: VirtualConsole) -> Self { + Self { vconsole } } fn draw(&mut self, mut out: impl io::Write) -> anyhow::Result<()> { From 4889c16f3d1f639745df72e04876108ea76a1c7a Mon Sep 17 00:00:00 2001 From: Riey Date: Fri, 14 Oct 2022 12:03:26 +0900 Subject: [PATCH 8/8] Assert instruction size --- Cargo.lock | 7 +++++++ crates/erars-compiler/Cargo.toml | 1 + crates/erars-compiler/src/instruction.rs | 2 ++ 3 files changed, 10 insertions(+) diff --git a/Cargo.lock b/Cargo.lock index a29d1356..1376cc22 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -678,6 +678,7 @@ dependencies = [ "option_set", "serde", "smol_str", + "static_assertions", "strum", "thiserror", "unicode-xid", @@ -1796,6 +1797,12 @@ dependencies = [ "lock_api", ] +[[package]] +name = "static_assertions" +version = "1.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a2eb9349b6444b326872e140eb1cf5e7c522154d69e7a0ffb0fb81c06b37543f" + [[package]] name = "strsim" version = "0.10.0" diff --git a/crates/erars-compiler/Cargo.toml b/crates/erars-compiler/Cargo.toml index c03f5d0a..91eaae83 100644 --- a/crates/erars-compiler/Cargo.toml +++ b/crates/erars-compiler/Cargo.toml @@ -24,6 +24,7 @@ unicode-xid = "0.2.3" smol_str = { version = "0.1.23", features = ["serde"] } log = "0.4.17" derivative = "2.2.0" +static_assertions = "1.1.0" [dev-dependencies] k9 = "0.11.1" diff --git a/crates/erars-compiler/src/instruction.rs b/crates/erars-compiler/src/instruction.rs index 61ba9e66..4ac7691f 100644 --- a/crates/erars-compiler/src/instruction.rs +++ b/crates/erars-compiler/src/instruction.rs @@ -3,6 +3,8 @@ use erars_ast::{ EventType, NotNan, PrintFlags, ScriptPosition, StrKey, UnaryOperator, }; +static_assertions::assert_eq_size!(Instruction, (i64, i64)); + #[derive(Clone, Copy, Debug, Eq, PartialEq)] pub enum Instruction { Nop,