use crate::{
c_bool, compile, data_kind, panic, util, AlterCol, AssignOp, Block, ColInfo, DataType, EvalEnv,
Expr, ExprIs, FromExpression, IndexInfo, Instruction, ObjRef, Rc, SqlError, TableExpression,
Token, Transaction, Value, BINARY, BOOL, DB, DO, DOUBLE, FLOAT, INT, NONE, STRING,
};
use compile::{c_delete, c_for, c_function, c_select, c_set, c_table, c_te, c_update, push};
use std::{mem, str};
use Instruction::{Call, Execute, Jump, JumpIfFalse, PopToLocal, Return, Select, Throw};
pub struct Parser<'a> {
pub b: Block<'a>,
pub function_name: Option<&'a ObjRef>,
source: &'a [u8],
source_ix: usize,
cc: u8,
token: Token,
token_start: usize,
token_space_start: usize,
cs: &'a [u8],
ts: String,
source_column: usize,
source_line: usize,
decimal_int: i64,
prev_source_column: usize,
prev_source_line: usize,
}
impl<'a> Parser<'a> {
pub fn new(src: &'a str, db: &DB) -> Self {
let source = src.as_bytes();
let mut result = Self {
source,
function_name: None,
source_ix: 0,
cc: 0,
token_start: 0,
token_space_start: 0,
token: Token::EndOfFile,
cs: source,
ts: String::new(),
source_column: 1,
source_line: 1,
prev_source_column: 1,
prev_source_line: 1,
decimal_int: 0,
b: Block::new(db.clone()),
};
result.read_char();
result.read_token();
result
}
fn statement(&mut self) {
if self.token == Token::Id {
let id = self.cs;
self.read_token();
if self.test(Token::Colon) {
self.b.set_goto_label(id);
} else {
match id {
b"ALTER" => self.s_alter(),
b"BEGIN" => self.s_begin(),
b"BREAK" => self.s_break(),
b"CREATE" => self.s_create(),
b"DROP" => self.s_drop(),
b"DECLARE" => self.s_declare(),
b"DELETE" => self.s_delete(),
b"EXEC" => self.s_exec(),
b"CHECK" => self.s_check(),
b"EXECUTE" => self.s_execute(),
b"FOR" => self.s_for(),
b"GOTO" => self.s_goto(),
b"IF" => self.s_if(),
b"INSERT" => self.s_insert(),
b"RETURN" => self.s_return(),
b"SELECT" => self.s_select(),
b"SET" => self.s_set(),
b"THROW" => self.s_throw(),
b"UPDATE" => self.s_update(),
b"WHILE" => self.s_while(),
_ => panic!("statement keyword expected, got '{}'", tos(id)),
}
}
} else {
panic!("statement keyword expected, got '{:?}'", self.token)
}
} pub fn batch(&mut self, rs: &mut dyn Transaction) {
loop {
while self.token != Token::EndOfFile && !self.test_id(b"GO") {
self.statement();
}
self.b.resolve_jumps();
let mut ee = EvalEnv::new(self.b.db.clone(), rs);
ee.alloc_locals(&self.b.local_typ, 0);
ee.go(&self.b.ilist);
if self.token == Token::EndOfFile {
break;
}
self.b = Block::new(self.b.db.clone());
}
}
pub fn parse_function(&mut self) {
self.read(Token::LBra);
while self.token == Token::Id {
let name = self.id_ref();
let typ = self.read_data_type();
self.b.def_local(name, typ);
self.b.param_count += 1;
if self.token == Token::RBra {
break;
}
assert!(
self.token == Token::Comma,
"comma or closing bracket expected"
);
self.read_token();
}
self.read(Token::RBra);
self.b.return_type = if
self.cs == b"RETURNS" {
self.read_id(b"RETURNS");
self.read_data_type()
} else {
NONE
};
if self.b.return_type != NONE {
self.b.def_local(b"result", self.b.return_type);
}
self.read_id(b"AS");
self.read_id(b"BEGIN");
self.s_begin();
self.b.resolve_jumps();
}
fn read_char(&mut self) -> u8 {
let cc;
if self.source_ix >= self.source.len() {
cc = 0;
self.source_ix = self.source.len() + 1;
} else {
cc = self.source[self.source_ix];
if cc == b'\n' {
self.source_column = 1;
self.source_line += 1;
} else if (cc & 192) != 128
{
self.source_column += 1;
}
self.source_ix += 1;
}
self.cc = cc;
cc
}
fn read_token(&mut self) {
self.token_space_start = self.source_ix - 1;
self.prev_source_line = self.source_line;
self.prev_source_column = self.source_column;
let mut cc = self.cc;
let mut token;
'skip_space: loop {
while cc == b' ' || cc == b'\n' || cc == b'\r' {
cc = self.read_char();
}
self.token_start = self.source_ix - 1;
let sc: u8 = cc;
cc = self.read_char();
match sc {
b'A'..=b'Z' | b'a'..=b'z' | b'@' => {
token = Token::Id;
while cc.is_ascii_alphabetic() {
cc = self.read_char();
}
self.cs = &self.source[self.token_start..self.source_ix - 1];
}
b'0'..=b'9' => {
token = Token::Number;
let fc = self.source[self.token_start];
if fc == b'0' && cc == b'x' {
cc = self.read_char();
token = Token::Hex;
while cc.is_ascii_hexdigit() {
cc = self.read_char();
}
} else {
while cc.is_ascii_digit() {
cc = self.read_char();
}
let part1 = self.source_ix - 1;
let s = str::from_utf8(&self.source[self.token_start..part1]).unwrap();
self.decimal_int = s.parse().unwrap();
}
self.cs = &self.source[self.token_start..self.source_ix - 1];
}
b'[' => {
token = Token::Id;
let start = self.source_ix - 1;
while cc != 0 {
if cc == b']' {
self.read_char();
break;
}
cc = self.read_char();
}
self.cs = &self.source[start..self.source_ix - 2];
}
b'\'' => {
token = Token::String;
let mut start = self.source_ix - 1;
self.ts = String::new();
loop {
assert!(cc != 0, "missing closing quote for string literal");
if cc == b'\'' {
cc = self.read_char();
if cc != b'\'' {
break;
}
self.ts.push_str(
str::from_utf8(&self.source[start..self.source_ix - 1]).unwrap(),
);
start = self.source_ix;
}
cc = self.read_char();
}
self.ts
.push_str(str::from_utf8(&self.source[start..self.source_ix - 2]).unwrap());
break;
}
b'/' => {
token = Token::Divide;
if cc == b'*'
{
cc = self.read_char();
let mut prevchar = b'X';
while (cc != b'/' || prevchar != b'*') && cc != 0 {
prevchar = cc;
cc = self.read_char();
}
cc = self.read_char();
continue 'skip_space;
}
}
b'>' => {
token = Token::Greater;
if cc == b'=' {
token = Token::GreaterEqual;
self.read_char();
}
}
b'<' => {
token = Token::Less;
if cc == b'=' {
token = Token::LessEqual;
self.read_char();
} else if cc == b'>' {
token = Token::NotEqual;
self.read_char();
}
}
b'!' => {
token = Token::Exclamation;
if cc == b'=' {
token = Token::NotEqual;
self.read_char();
}
}
b'(' => token = Token::LBra,
b')' => token = Token::RBra,
b'|' => {
token = Token::VBar;
if cc == b'=' {
token = Token::VBarEqual;
self.read_char();
}
}
b'+' => {
token = Token::Plus;
if cc == b'=' {
token = Token::PlusEqual;
self.read_char();
}
}
b'-' => {
token = Token::Minus;
if cc == b'-'
{
while cc != b'\n' && cc != 0 {
cc = self.read_char();
}
continue 'skip_space;
} else if cc == b'=' {
token = Token::MinusEqual;
self.read_char();
}
}
b',' => token = Token::Comma,
b'.' => token = Token::Dot,
b'=' => token = Token::Equal,
b':' => token = Token::Colon,
b'*' => token = Token::Times,
b'%' => token = Token::Percent,
0 => token = Token::EndOfFile,
_ => token = Token::Unknown,
}
break;
} self.token = token;
}
fn source_from(&self, start: usize, end: usize) -> String {
to_s(&self.source[start..end])
}
fn read_data_type(&mut self) -> DataType {
assert!(self.token == Token::Id, "datatype expected");
let mut t = match self.id_ref() {
b"int" => INT,
b"string" => STRING,
b"binary" => BINARY,
b"float" => FLOAT,
b"double" => DOUBLE,
b"bool" => BOOL,
_ => panic!("datatype expected"),
};
if self.test(Token::LBra) {
let mut n = self.decimal_int as usize;
self.read(Token::Number);
self.read(Token::RBra);
match t {
BINARY | STRING => {
n += 1;
if n > 250 {
n = 250;
}
if n < 9 {
n = 9;
}
}
INT => {
assert!(n >= 1, "minimum int precision is 1");
assert!(n <= 8, "maximum int precision is 8");
}
_ => panic!("invalid data type specification"),
}
t = (t % 8) + (8 * n);
}
t
}
fn operator(&mut self) -> (Token, i8) {
let mut t = self.token;
if t >= Token::Id {
if t == Token::Id {
t = match self.cs {
b"AND" => Token::And,
b"OR" => Token::Or,
b"IN" => Token::In,
_ => return (t, -1),
}
} else {
return (t, -1);
}
}
(t, t.precedence())
}
fn id(&mut self) -> String {
to_s(self.id_ref())
}
fn id_ref(&mut self) -> &'a [u8] {
assert!(self.token == Token::Id, "name expected");
let result = self.cs;
self.read_token();
result
}
fn local(&mut self) -> usize {
let result: usize;
assert!(self.token == Token::Id, "name expected");
if let Some(lnum) = self.b.get_local(self.cs) {
result = *lnum;
} else {
panic!("undeclared local: {}", tos(self.cs))
}
self.read_token();
result
}
fn read(&mut self, t: Token) {
if self.token != t {
panic!("expected '{:?}' got '{:?}'", t, self.token)
} else {
self.read_token();
}
}
fn read_id(&mut self, s: &[u8]) {
if self.token != Token::Id || self.cs != s {
panic!("expected '{}' got '{}'", tos(s), tos(self.cs));
} else {
self.read_token();
}
}
fn test(&mut self, t: Token) -> bool {
let result = self.token == t;
if result {
self.read_token();
}
result
}
fn test_id(&mut self, s: &[u8]) -> bool {
if self.token != Token::Id || self.cs != s {
false
} else {
self.read_token();
true
}
}
fn obj_ref(&mut self) -> ObjRef {
let schema = self.id();
self.read(Token::Dot);
let name = self.id();
ObjRef { schema, name }
}
fn rname(&self) -> String {
if let Some(name) = self.function_name {
name.str()
} else {
"batch".to_string()
}
}
pub(crate) fn make_error(&self, msg: String) -> SqlError {
SqlError {
line: self.prev_source_line,
column: self.prev_source_column,
msg,
rname: self.rname(),
}
}
fn exp_id(&mut self) -> Expr {
let name = self.id_ref();
if self.test(Token::Dot) {
let fname = self.id_ref();
let mut parms = Vec::new();
self.read(Token::LBra);
if self.token != Token::RBra {
loop {
parms.push(self.exp());
if !self.test(Token::Comma) {
break;
}
}
}
self.read(Token::RBra);
let name = ObjRef {
schema: to_s(name),
name: to_s(fname),
};
Expr::new(ExprIs::FuncCall(name, parms))
} else if self.test(Token::LBra) {
let mut parms = Vec::new();
if self.token != Token::RBra {
loop {
parms.push(self.exp());
if !self.test(Token::Comma) {
break;
}
}
}
self.read(Token::RBra);
Expr::new(ExprIs::BuiltinCall(to_s(name), parms))
} else if name == b"true" {
Expr::new(ExprIs::Const(Value::Bool(true)))
} else if name == b"false" {
Expr::new(ExprIs::Const(Value::Bool(false)))
} else if let Some(lnum) = self.b.get_local(name) {
Expr::new(ExprIs::Local(*lnum))
} else {
Expr::new(ExprIs::ColName(to_s(name)))
}
}
fn exp_primary(&mut self) -> Expr {
let result;
if self.token == Token::Id {
result = if self.test_id(b"CASE") {
self.exp_case()
} else if self.test_id(b"NOT") {
let e = self.exp_p(10); Expr::new(ExprIs::Not(Box::new(e)))
} else {
self.exp_id()
};
} else if self.test(Token::LBra) {
if self.test_id(b"SELECT") {
result = self.exp_scalar_select();
} else {
let exp = self.exp();
if self.test(Token::Comma)
{
let mut list = vec![exp];
loop {
list.push(self.exp());
if !self.test(Token::Comma) {
break;
}
}
result = Expr::new(ExprIs::List(list));
} else {
result = exp;
}
}
self.read(Token::RBra);
} else if self.token == Token::String {
result = Expr::new(ExprIs::Const(Value::String(Rc::new(self.ts.clone()))));
self.read_token();
} else if self.token == Token::Number {
let value = self.decimal_int;
result = Expr::new(ExprIs::Const(Value::Int(value)));
self.read_token();
} else if self.token == Token::Hex {
assert!(
self.cs.len() % 2 == 0,
"hex literal must have even number of characters"
);
let hb = &self.source[self.token_start + 2..self.source_ix - 1];
result = Expr::new(ExprIs::Const(Value::RcBinary(Rc::new(util::parse_hex(hb)))));
self.read_token();
} else if self.test(Token::Minus) {
result = Expr::new(ExprIs::Minus(Box::new(self.exp_p(30))));
} else {
panic!("expression expected")
}
result
}
fn exp_or_agg(&mut self) -> Expr {
let pri = self.exp_primary();
self.exp_lp(pri, 0)
}
fn exp(&mut self) -> Expr {
self.exp_p(0)
}
fn exp_p(&mut self, precedence: i8) -> Expr {
let pr = self.exp_primary();
self.exp_lp(pr, precedence)
}
fn exp_lp(&mut self, mut lhs: Expr, precedence: i8) -> Expr {
let mut t = self.operator();
while t.1 >= precedence {
let op = t;
self.read_token();
let mut rhs = self.exp_primary();
t = self.operator();
while t.1 > op.1
{
rhs = self.exp_lp(rhs, t.1);
t = self.operator();
}
lhs = Expr::new(ExprIs::Binary(op.0, Box::new(lhs), Box::new(rhs)));
}
lhs
}
fn exp_case(&mut self) -> Expr {
let mut list = Vec::new();
while self.test_id(b"WHEN") {
let test = self.exp();
self.read_id(b"THEN");
let e = self.exp();
list.push((test, e));
}
assert!(!list.is_empty(), "empty CASE expression");
self.read_id(b"ELSE");
let els = Box::new(self.exp());
self.read_id(b"END");
Expr::new(ExprIs::Case(list, els))
}
fn exp_scalar_select(&mut self) -> Expr {
let te = self.select_expression(false);
Expr::new(ExprIs::ScalarSelect(Box::new(te)))
}
fn insert_expression(&mut self, expect: usize) -> TableExpression {
self.read_id(b"VALUES");
let mut values = Vec::new();
while self.test(Token::LBra) {
let mut v = Vec::new();
loop {
v.push(self.exp());
if self.test(Token::RBra) {
break;
}
assert!(
self.token == Token::Comma,
"comma or closing bracket expected"
);
self.read_token();
}
assert!(v.len() == expect, "wrong number of values");
values.push(v);
if !self.test(Token::Comma) && self.token != Token::LBra {
break;
} }
TableExpression::Values(values)
}
fn te_named_table(&mut self) -> TableExpression {
let schema = self.id();
self.read(Token::Dot);
let name = self.id();
let name = ObjRef { schema, name };
TableExpression::Base(name)
}
fn primary_table_exp(&mut self) -> TableExpression {
assert!(self.token == Token::Id, "table name expected");
self.te_named_table()
}
fn exp_name(&self, exp: &Expr) -> String {
match &exp.exp {
ExprIs::Local(num) => to_s(self.b.local_name(*num)),
ExprIs::ColName(name) => name.to_string(),
_ => "".to_string(),
}
}
fn select_expression(&mut self, set_or_for: bool) -> FromExpression {
let mut exps = Vec::new();
let mut colnames = Vec::new();
let mut assigns = Vec::new();
loop {
if set_or_for {
let local = self.local();
let op = match self.token {
Token::Equal => AssignOp::Assign,
Token::VBarEqual => AssignOp::Append,
Token::PlusEqual => AssignOp::Inc,
Token::MinusEqual => AssignOp::Dec,
_ => panic!("assign operator expected"),
};
self.read_token();
assigns.push((local, op));
}
let exp = self.exp_or_agg();
if self.test_id(b"AS") {
colnames.push(self.id());
} else {
colnames.push(self.exp_name(&exp));
}
exps.push(exp);
if !self.test(Token::Comma) {
break;
}
}
let from = if self.test_id(b"FROM") {
Some(Box::new(self.primary_table_exp()))
} else {
None
};
let wher = if self.test_id(b"WHERE") {
Some(self.exp())
} else {
None
};
let mut orderby = Vec::new();
if self.test_id(b"ORDER") {
self.read_id(b"BY");
loop {
let exp = self.exp();
let desc = if self.test_id(b"DESC") {
true
} else {
self.test_id(b"ASC");
false
};
orderby.push((exp, desc));
if !self.test(Token::Comma) {
break;
}
}
}
FromExpression {
colnames,
assigns,
exps,
from,
wher,
orderby,
}
}
fn s_select(&mut self) {
let se = self.select_expression(false);
if !self.b.parse_only {
let cte = c_select(&mut self.b, se);
self.b.add(Select(Box::new(cte)));
}
}
fn s_set(&mut self) {
let se = self.select_expression(true);
if !self.b.parse_only {
c_set(&mut self.b, se);
}
}
fn s_insert(&mut self) {
self.read_id(b"INTO");
let tr = self.obj_ref();
self.read(Token::LBra);
let mut cnames = Vec::new();
loop {
let cname = self.id_ref();
assert!(!cnames.contains(&cname), "duplicate column name");
cnames.push(cname);
if self.test(Token::RBra) {
break;
}
assert!(self.test(Token::Comma), "comma or closing bracket expected");
}
let mut src = self.insert_expression(cnames.len());
if !self.b.parse_only {
let t = c_table(&self.b, &tr);
let mut cnums: Vec<usize> = Vec::new();
{
for cname in &cnames {
if let Some(cnum) = t.info.get(tos(cname)) {
cnums.push(*cnum);
} else {
panic!("column name '{}' not found", tos(cname))
}
}
}
let csrc = c_te(&self.b, &mut src);
self.b.dop(DO::Insert(t, cnums, csrc));
}
}
fn s_update(&mut self) {
let tname = self.obj_ref();
self.read_id(b"SET");
let mut assigns = Vec::new();
loop {
let name = self.id();
self.read(Token::Equal);
let exp = self.exp();
assigns.push((name, exp));
if !self.test(Token::Comma) {
break;
}
}
assert!(self.test_id(b"WHERE"), "UPDATE must have a WHERE");
let mut wher = Some(self.exp());
if !self.b.parse_only {
c_update(&mut self.b, &tname, &mut assigns, &mut wher);
}
}
fn s_delete(&mut self) {
self.read_id(b"FROM");
let tname = self.obj_ref();
assert!(self.test_id(b"WHERE"), "DELETE must have a WHERE");
let mut wher = Some(self.exp());
if !self.b.parse_only {
c_delete(&mut self.b, &tname, &mut wher);
}
}
fn s_execute(&mut self) {
self.read(Token::LBra);
let mut exp = self.exp();
self.read(Token::RBra);
if !self.b.parse_only {
push(&mut self.b, &mut exp);
self.b.add(Execute);
}
}
fn s_check(&mut self) {
let name = self.obj_ref();
if !self.b.parse_only {
c_function(&self.b.db, &name);
}
}
fn s_exec(&mut self) {
let mut pname = self.id();
let mut sname = "".to_string();
if self.test(Token::Dot) {
sname = pname;
pname = self.id();
}
let name = ObjRef {
schema: sname,
name: pname,
};
self.read(Token::LBra);
let mut pkinds = Vec::new();
if !self.test(Token::RBra) {
let mut e = self.exp();
pkinds.push(push(&mut self.b, &mut e));
while self.test(Token::Comma) {
let mut e = self.exp();
pkinds.push(push(&mut self.b, &mut e));
}
self.read(Token::RBra);
}
if !self.b.parse_only {
let func = c_function(&self.b.db, &name);
assert!(
func.return_type == NONE,
"EXEC function cannot have a return type"
);
self.b.check_types(&func, &pkinds);
self.b.add(Call(func));
}
}
fn s_for(&mut self) {
let se: FromExpression = self.select_expression(true);
let for_id = self.b.local_typ.len();
self.b.local_typ.push(NONE);
let start_id = self.b.get_jump_id();
let break_id = self.b.get_jump_id();
if !self.b.parse_only {
c_for(&mut self.b, se, start_id, break_id, for_id);
}
let save = self.b.break_id;
self.b.break_id = break_id;
self.statement();
self.b.break_id = save;
self.b.add(Jump(start_id));
self.b.set_jump(break_id);
}
fn create_table(&mut self) {
let name = self.obj_ref();
let source_start = self.source_ix - 2;
self.read(Token::LBra);
let mut ti = ColInfo::empty(name);
while !self.test(Token::RBra) {
let cname = self.id();
let typ = self.read_data_type();
assert!(!ti.add(cname, typ), "duplicate column name");
self.test(Token::Comma);
}
if !self.b.parse_only {
let _source = self.source_from(source_start, self.token_start);
self.b.dop(DO::CreateTable(ti));
}
}
fn create_index(&mut self) {
let iname = self.id();
self.read_id(b"ON");
let tname = self.obj_ref();
self.read(Token::LBra);
let mut cnames = Vec::new();
loop {
cnames.push(self.id());
if self.test(Token::RBra) {
break;
}
assert!(
self.token == Token::Comma,
"comma or closing bracket expected"
);
self.read_token();
}
if !self.b.parse_only {
let mut cols = Vec::new();
let table = c_table(&self.b, &tname);
for cname in &cnames {
if let Some(cnum) = table.info.colmap.get(cname) {
cols.push(*cnum);
} else {
panic!("index column name not found {}", cname);
}
}
self.b
.dop(DO::CreateIndex(IndexInfo { tname, iname, cols }));
}
}
fn create_function(&mut self, alter: bool) {
let rref: ObjRef = self.obj_ref();
let source_start: usize = self.source_ix - 2;
let db = self.b.db.clone();
let save: Block = mem::replace(&mut self.b, Block::new(db));
let save2: bool = self.b.parse_only;
self.b.parse_only = true;
self.parse_function();
let _cb: Block = mem::replace(&mut self.b, save);
self.b.parse_only = save2;
if !self.b.parse_only {
let source: String = self.source_from(source_start, self.token_space_start);
self.b.dop(DO::CreateFunction(rref, Rc::new(source), alter));
}
}
fn s_create(&mut self) {
match self.id_ref() {
b"FN" => self.create_function(false),
b"TABLE" => self.create_table(),
b"SCHEMA" => {
let name = self.id();
self.b.dop(DO::CreateSchema(name));
}
b"INDEX" => self.create_index(),
_ => panic!("CREATE : TABLE<FN.. expected"),
}
}
fn s_alter(&mut self) {
match self.id_ref() {
b"FN" => self.create_function(true),
b"TABLE" => self.s_alter_table(),
_ => panic!("ALTER : TABLE,FN.. expected"),
}
}
fn s_drop(&mut self) {
match self.id_ref() {
b"TABLE" => {
let tr = self.obj_ref();
self.b.dop(DO::DropTable(tr));
}
b"INDEX" => {
let ix = self.id();
self.read_id(b"ON");
let tr = self.obj_ref();
self.b.dop(DO::DropIndex(tr, ix));
}
b"FN" => {
let fr = self.obj_ref();
self.b.dop(DO::DropFunction(fr));
}
b"SCHEMA" => {
let s = self.id();
self.b.dop(DO::DropSchema(s));
}
_ => {
panic!("DROP : TABLE,FN .. expected");
}
}
}
fn s_alter_table(&mut self) {
let tr = self.obj_ref();
let mut list = Vec::new();
loop {
if self.test_id(b"ADD") {
let col = self.id();
let datatype = self.read_data_type();
list.push(AlterCol::Add(col, datatype));
} else if self.test_id(b"DROP") {
let col = self.id();
list.push(AlterCol::Drop(col));
} else if self.test_id(b"MODIFY") {
let col = self.id();
let datatype = self.read_data_type();
list.push(AlterCol::Modify(col, datatype));
} else {
break;
}
if !self.test(Token::Comma) {
break;
}
}
self.b.dop(DO::AlterTable(tr, list));
}
fn s_declare(&mut self) {
loop {
let name = self.id_ref();
let dt = self.read_data_type();
self.b.def_local(name, dt);
if !self.test(Token::Comma) {
break;
}
}
}
fn s_while(&mut self) {
let mut exp = self.exp();
let start_id = self.b.get_loop_id();
let break_id = self.b.get_jump_id();
if !self.b.parse_only {
let exp = c_bool(&self.b, &mut exp);
self.b.add(JumpIfFalse(break_id, exp));
let save = self.b.break_id;
self.b.break_id = break_id;
self.statement();
self.b.break_id = save;
self.b.add(Jump(start_id));
self.b.set_jump(break_id);
}
}
fn s_if(&mut self) {
let mut exp = self.exp();
let false_id = self.b.get_jump_id();
if !self.b.parse_only {
let exp = c_bool(&self.b, &mut exp);
self.b.add(JumpIfFalse(false_id, exp));
}
self.statement();
if self.test_id(b"ELSE") {
let end_id = self.b.get_jump_id();
self.b.add(Jump(end_id)); self.b.set_jump(false_id);
self.statement();
self.b.set_jump(end_id);
} else {
self.b.set_jump(false_id);
}
}
fn s_goto(&mut self) {
let label = self.id_ref();
let to = self.b.get_goto_label(label);
self.b.add(Jump(to));
}
fn s_break(&mut self) {
let break_id = self.b.break_id;
assert!(break_id != usize::MAX, "no enclosing loop for break");
self.b.add(Jump(break_id));
}
fn s_return(&mut self) {
if self.b.return_type != NONE {
let mut e = self.exp();
if !self.b.parse_only {
let k = push(&mut self.b, &mut e);
let rk = data_kind(self.b.return_type);
assert!(k == rk, "return type mismatch expected {rk:?} got {k:?}");
self.b.add(PopToLocal(self.b.param_count));
}
}
self.b.add(Return);
}
fn s_throw(&mut self) {
let mut msg = self.exp();
if !self.b.parse_only {
push(&mut self.b, &mut msg);
self.b.add(Throw);
}
}
fn s_begin(&mut self) {
while !self.test_id(b"END") {
self.statement();
}
}
} pub fn tos(s: &[u8]) -> &str {
str::from_utf8(s).unwrap()
}
pub fn to_s(s: &[u8]) -> String {
str::from_utf8(s).unwrap().to_string()
}