authorgravatar for me@paperdave.netdave caruso <me@paperdave.net> 2024-01-22 02:14:22-08:00
committergravatar for me@paperdave.netdave caruso <me@paperdave.net> 2024-01-22 02:14:22-08:00
log42c364acbbbd54bf8afefa0ff82034928e83f06e
treee820c08f8d97f3bee28a0908a3853fe7481a548e
parentc164266ac2d05ed0a0f7ab09b8db76b5b81eb964
signature Commit is signed but in an unrecognized format.

fix some things


8 files changed, 125 insertions(+), 124 deletions(-)

crates/ast/ast.rs+9-19
...@@ -186,13 +186,6 @@ impl BuiltinId {...@@ -186,13 +186,6 @@ impl BuiltinId {
186}186}
187187
188impl Statement {188impl Statement {
189 pub fn is_expression(&self) -> bool {
190 match &self {
191 Statement::Expr(_) => true,
192 _ => false,
193 }
194 }
195
196 pub fn to_top_level(self) -> TopLevelStatement {189 pub fn to_top_level(self) -> TopLevelStatement {
197 match self {190 match self {
198 Statement::Expr(expr) => TopLevelStatement::Expr(expr),191 Statement::Expr(expr) => TopLevelStatement::Expr(expr),
...@@ -201,18 +194,22 @@ impl Statement {...@@ -201,18 +194,22 @@ impl Statement {
201 }194 }
202 }195 }
203196
204 pub fn is_comment(&self) -> bool {197 /// This is stupid function im sorry
205 match self {198 pub fn require_semicolon(&self, semicolon_hint: bool) -> bool {
206 Statement::Comment(_) => true,199 match &self {
200 Statement::Expr(_) => !semicolon_hint,
201 Statement::Decl(_) => true,
207 _ => false,202 _ => false,
208 }203 }
209 }204 }
210}205}
211206
212impl TopLevelStatement {207impl TopLevelStatement {
213 pub fn is_expression(&self) -> bool {208 /// This is stupid function im sorry
209 pub fn require_semicolon(&self, earlier_hint: bool) -> bool {
214 match &self {210 match &self {
215 TopLevelStatement::Expr(_) => true,211 TopLevelStatement::Expr(_) => !earlier_hint,
212 TopLevelStatement::Decl(_) => true,
216 _ => false,213 _ => false,
217 }214 }
218 }215 }
...@@ -224,11 +221,4 @@ impl TopLevelStatement {...@@ -224,11 +221,4 @@ impl TopLevelStatement {
224 TopLevelStatement::Comment(comment) => Statement::Comment(comment),221 TopLevelStatement::Comment(comment) => Statement::Comment(comment),
225 }222 }
226 }223 }
227
228 pub fn is_comment(&self) -> bool {
229 match self {
230 TopLevelStatement::Comment(_) => true,
231 _ => false,
232 }
233 }
234}224}
crates/js_ast/hoist.rs+61-37
...@@ -2,6 +2,7 @@ use std::collections::{HashMap, HashSet};...@@ -2,6 +2,7 @@ use std::collections::{HashMap, HashSet};
2use std::vec;2use std::vec;
33
4use ast::{BinaryOperator, BlockOrIf, BlockWithLoc, Expr, Statement};4use ast::{BinaryOperator, BlockOrIf, BlockWithLoc, Expr, Statement};
5use has_side_effects::HasSideEffects;
5use tokenizer::Loc;6use tokenizer::Loc;
67
7use crate::*;8use crate::*;
...@@ -156,9 +157,7 @@ impl HoistContext {...@@ -156,9 +157,7 @@ impl HoistContext {
156 pub fn process_statement(&mut self, statement: Statement) -> Option<()> {157 pub fn process_statement(&mut self, statement: Statement) -> Option<()> {
157 if statement.is_valid_js_expression() {158 if statement.is_valid_js_expression() {
158 let result = convert_valid_statement(self, statement);159 let result = convert_valid_statement(self, statement);
159 if !result.is_literal() {160 self.add_statement(result);
160 self.add_statement(result);
161 }
162 return Some(());161 return Some(());
163 }162 }
164163
...@@ -189,13 +188,11 @@ impl HoistContext {...@@ -189,13 +188,11 @@ impl HoistContext {
189 Statement::Expr(expr) => {188 Statement::Expr(expr) => {
190 if let Some(expr) = self.hoist_expression_contents(expr) {189 if let Some(expr) = self.hoist_expression_contents(expr) {
191 let loc = expr.loc.clone();190 let loc = expr.loc.clone();
192 if !expr.is_literal() {191 self.add_statement(JsStatement::new(
193 self.add_statement(JsStatement::new(192 JsStatementData::Expression(expr),
194 JsStatementData::Expression(expr),193 loc,
195 loc,194 None,
196 None,195 ));
197 ))
198 }
199 Some(())196 Some(())
200 } else {197 } else {
201 None198 None
...@@ -209,9 +206,9 @@ impl HoistContext {...@@ -209,9 +206,9 @@ impl HoistContext {
209 /// and returns an identifier expression for it.206 /// and returns an identifier expression for it.
210 pub fn hoist_expression_to_temporary(&mut self, expr: Expr) -> Option<JsExpr> {207 pub fn hoist_expression_to_temporary(&mut self, expr: Expr) -> Option<JsExpr> {
211 // TODO208 // TODO
212 // if !expr.has_side_effects() {209 if !expr.has_side_effects() {
213 // return Some(self.hoist_expression_contents(expr)?);210 return Some(self.hoist_expression_contents(expr)?);
214 // }211 }
215212
216 let init = self.hoist_expression_contents(expr)?;213 let init = self.hoist_expression_contents(expr)?;
217214
...@@ -334,7 +331,7 @@ impl HoistContext {...@@ -334,7 +331,7 @@ impl HoistContext {
334 let mut did_assign = false;331 let mut did_assign = false;
335332
336 let js_if =333 let js_if =
337 self.hoist_js_if(data.yes, data.no, condition, &mut did_assign, &temporary)?;334 self.hoist_js_if(data.yes, data.no, condition, &mut did_assign, &temporary);
338335
339 self.add_statement(JsStatement::new(336 self.add_statement(JsStatement::new(
340 JsStatementData::If(js_if),337 JsStatementData::If(js_if),
...@@ -396,7 +393,7 @@ impl HoistContext {...@@ -396,7 +393,7 @@ impl HoistContext {
396 b: BlockWithLoc,393 b: BlockWithLoc,
397 temporary: &String,394 temporary: &String,
398 did_assign: &mut bool,395 did_assign: &mut bool,
399 ) -> Option<JsBlock> {396 ) -> JsBlock {
400 let loc = b.loc.clone();397 let loc = b.loc.clone();
401398
402 // A non-block will become a block with a single expression:399 // A non-block will become a block with a single expression:
...@@ -405,21 +402,22 @@ impl HoistContext {...@@ -405,21 +402,22 @@ impl HoistContext {
405 // We will also apply this transformation to blocks that are valid402 // We will also apply this transformation to blocks that are valid
406 // expressions, because that is more concise.403 // expressions, because that is more concise.
407 if b.is_valid_js_expression() {404 if b.is_valid_js_expression() {
408 return Some(JsBlock::new(405 return JsBlock::new(
409 vec![new_js_assignment_statement(406 vec![new_js_assignment_statement(
410 convert_valid_block(self, b),407 convert_valid_block(self, b),
411 temporary.clone(),408 temporary.clone(),
412 loc.clone(),409 loc.clone(),
413 )],410 )],
414 loc,411 loc,
415 ));412 );
416 }413 }
417414
418 let mut child = self.new_child();415 let mut child = self.new_child();
419416
420 for statement in b.block.statements {417 for statement in b.block.statements {
421 if let None = child.process_statement(statement) {418 if let None = child.process_statement(statement) {
422 return None;419 tree_shake_statement_list(&mut child.statements);
420 return JsBlock::new(child.statements, loc);
423 };421 };
424 }422 }
425423
...@@ -449,7 +447,9 @@ impl HoistContext {...@@ -449,7 +447,9 @@ impl HoistContext {
449 _ => {}447 _ => {}
450 }448 }
451449
452 Some(JsBlock::new(child.statements, loc))450 tree_shake_statement_list(&mut child.statements);
451
452 JsBlock::new(child.statements, loc)
453 }453 }
454454
455 pub fn hoist_block_to_arrow_fn_body(&mut self, b: BlockWithLoc) -> JsArrowBody {455 pub fn hoist_block_to_arrow_fn_body(&mut self, b: BlockWithLoc) -> JsArrowBody {
...@@ -494,6 +494,8 @@ impl HoistContext {...@@ -494,6 +494,8 @@ impl HoistContext {
494 _ => {}494 _ => {}
495 }495 }
496496
497 tree_shake_statement_list(&mut child.statements);
498
497 JsArrowBody::Block(JsBlock::new(child.statements, loc))499 JsArrowBody::Block(JsBlock::new(child.statements, loc))
498 }500 }
499501
...@@ -513,16 +515,9 @@ impl HoistContext {...@@ -513,16 +515,9 @@ impl HoistContext {
513 // to assign to the temporary variable.515 // to assign to the temporary variable.
514 match self.last_statement().map(|x| &x.data) {516 match self.last_statement().map(|x| &x.data) {
515 Some(JsStatementData::Expression(_)) if b.block.has_implicit_return => {517 Some(JsStatementData::Expression(_)) if b.block.has_implicit_return => {
516 let last = self.statements.pop().unwrap();518 match self.statements.pop().unwrap().data {
517 match last {519 JsStatementData::Expression(expr) => expr,
518 JsStatement {520 _ => unreachable!(),
519 data: JsStatementData::Expression(expr),
520 ..
521 } => expr,
522 _ => {
523 self.statements.push(last);
524 JsExpr::new(JsExprData::Null, loc.clone(), None)
525 }
526 }521 }
527 }522 }
528 _ => JsExpr::new(JsExprData::Null, loc.clone(), None),523 _ => JsExpr::new(JsExprData::Null, loc.clone(), None),
...@@ -536,15 +531,15 @@ impl HoistContext {...@@ -536,15 +531,15 @@ impl HoistContext {
536 condition: JsExpr,531 condition: JsExpr,
537 did_assign: &mut bool,532 did_assign: &mut bool,
538 temporary: &TempId,533 temporary: &TempId,
539 ) -> Option<JsIf> {534 ) -> JsIf {
540 let yes = self.hoist_block_to_js_block(yes, &temporary.get(&self), did_assign)?;535 let yes = self.hoist_block_to_js_block(yes, &temporary.get(&self), did_assign);
541536
542 let no = match no {537 let no = match no {
543 Some(BlockOrIf::Block(no)) => Some(JsElse::Block(self.hoist_block_to_js_block(538 Some(BlockOrIf::Block(no)) => Some(JsElse::Block(self.hoist_block_to_js_block(
544 no,539 no,
545 &temporary.get(&self),540 &temporary.get(&self),
546 did_assign,541 did_assign,
547 )?)),542 ))),
548 Some(BlockOrIf::If(else_if)) => {543 Some(BlockOrIf::If(else_if)) => {
549 // If the condition of this block has a side effect, we need to544 // If the condition of this block has a side effect, we need to
550 // emit a block so that we can assign to the temporary variable.545 // emit a block so that we can assign to the temporary variable.
...@@ -558,11 +553,12 @@ impl HoistContext {...@@ -558,11 +553,12 @@ impl HoistContext {
558 condition,553 condition,
559 did_assign,554 did_assign,
560 temporary,555 temporary,
561 )?)))556 ))))
562 } else {557 } else {
563 let mut temp_block = self.new_child();558 let mut temp_block = self.new_child();
564 let condition =559 let condition = temp_block
565 temp_block.hoist_expression_to_temporary(*else_if.condition.clone())?;560 .hoist_expression_to_temporary(*else_if.condition.clone())
561 .unwrap();
566562
567 temp_block.add_statement(JsStatement::new(563 temp_block.add_statement(JsStatement::new(
568 JsStatementData::If(self.hoist_js_if(564 JsStatementData::If(self.hoist_js_if(
...@@ -571,11 +567,13 @@ impl HoistContext {...@@ -571,11 +567,13 @@ impl HoistContext {
571 condition,567 condition,
572 did_assign,568 did_assign,
573 temporary,569 temporary,
574 )?),570 )),
575 Loc::EMPTY,571 Loc::EMPTY,
576 None,572 None,
577 ));573 ));
578574
575 tree_shake_statement_list(&mut temp_block.statements);
576
579 Some(JsElse::Block(JsBlock::new(577 Some(JsElse::Block(JsBlock::new(
580 temp_block.statements,578 temp_block.statements,
581 Loc::EMPTY,579 Loc::EMPTY,
...@@ -585,7 +583,7 @@ impl HoistContext {...@@ -585,7 +583,7 @@ impl HoistContext {
585 None => None,583 None => None,
586 };584 };
587585
588 Some(JsIf { condition, yes, no })586 JsIf { condition, yes, no }
589 }587 }
590}588}
591589
...@@ -612,3 +610,29 @@ pub fn new_js_assignment_expr(expr: JsExpr, target: String, loc: Loc) -> JsExpr...@@ -612,3 +610,29 @@ pub fn new_js_assignment_expr(expr: JsExpr, target: String, loc: Loc) -> JsExpr
612 None,610 None,
613 )611 )
614}612}
613
614/// Remove
615/// - Discarded literals
616pub fn tree_shake_statement_list(list: &mut Vec<JsStatement>) {
617 let mut set_i = 0;
618 for i in 0..list.len() {
619 let stmt = list.get(i).unwrap();
620 let should_keep = match &stmt.data {
621 JsStatementData::Expression(expr) => !expr.is_literal(),
622 JsStatementData::Return(_) => true,
623 JsStatementData::Export(_) => true,
624 JsStatementData::Declaration(_) => true,
625 JsStatementData::Function(_) => true,
626 JsStatementData::If(_) => true,
627 //
628 };
629
630 if should_keep {
631 if set_i != i {
632 list.swap(i, set_i)
633 }
634 set_i += 1;
635 }
636 }
637 list.truncate(set_i)
638}
crates/js_ast/js_ast.rs-7
...@@ -176,13 +176,6 @@ impl JsStatement {...@@ -176,13 +176,6 @@ impl JsStatement {
176 pub fn new(data: JsStatementData, loc: Loc, comment: Option<Comment>) -> Self {176 pub fn new(data: JsStatementData, loc: Loc, comment: Option<Comment>) -> Self {
177 Self { data, loc, comment }177 Self { data, loc, comment }
178 }178 }
179
180 pub(crate) fn is_literal(&self) -> bool {
181 match &self.data {
182 JsStatementData::Expression(expr) => expr.is_literal(),
183 _ => false,
184 }
185 }
186}179}
187180
188#[derive(Debug, PartialEq, Clone)]181#[derive(Debug, PartialEq, Clone)]
crates/parser/parse_block.rs+2-8
...@@ -46,10 +46,7 @@ pub fn parse_block(p: &mut Parser) -> Result<Block> {...@@ -46,10 +46,7 @@ pub fn parse_block(p: &mut Parser) -> Result<Block> {
46 },46 },
47 Some(Token::ClosedBrace) => {47 Some(Token::ClosedBrace) => {
48 p.next();48 p.next();
49 if !statement.is_expression()49 if statement.require_semicolon(is_statement_like_expression) {
50 && !statement.is_comment()
51 && is_statement_like_expression
52 {
53 p.is_top_level = was_top_level;50 p.is_top_level = was_top_level;
54 return Err(p51 return Err(p
55 .error("Expected semicolon or '}' after statement".to_string())52 .error("Expected semicolon or '}' after statement".to_string())
...@@ -63,10 +60,7 @@ pub fn parse_block(p: &mut Parser) -> Result<Block> {...@@ -63,10 +60,7 @@ pub fn parse_block(p: &mut Parser) -> Result<Block> {
63 });60 });
64 }61 }
65 _ => {62 _ => {
66 if !statement.is_expression()63 if statement.require_semicolon(is_statement_like_expression) {
67 && !statement.is_comment()
68 && is_statement_like_expression
69 {
70 p.is_top_level = was_top_level;64 p.is_top_level = was_top_level;
71 return Err(p65 return Err(p
72 .error("Expected semicolon or '}' after statement".to_string())66 .error("Expected semicolon or '}' after statement".to_string())
crates/parser/parse_module.rs+1-1
...@@ -24,7 +24,7 @@ pub fn parse_module(p: &mut Parser) -> Result<Module> {...@@ -24,7 +24,7 @@ pub fn parse_module(p: &mut Parser) -> Result<Module> {
24 }24 }
25 }25 }
26 _ => {26 _ => {
27 if !statement.is_comment() && is_statement_like_expression {27 if statement.require_semicolon(is_statement_like_expression) {
28 return Err(p28 return Err(p
29 .error("Expected semicolon after statement".to_string())29 .error("Expected semicolon after statement".to_string())
30 .into());30 .into());
crates/sema/ast_type_coersion.rs+51-51
...@@ -1,54 +1,54 @@...@@ -1,54 +1,54 @@
1// use ast::{BinaryOperator, ExprData, Type};1// use ast::{BinaryOperator, ExprData, Type};
22
3// impl TypeCoerceable for ExprData {3impl TypeCoerceable for ExprData {
4// fn to_type(&self) -> Option<Type> {4 fn to_type(&self) -> Option<Type> {
5// match self {5 match self {
6// ExprData::Block(block) => {6 ExprData::Block(block) => {
7// if (block.has_implicit_return) {7 if (block.has_implicit_return) {
8// block.statements.last().unwrap().to_type()8 block.statements.last().unwrap().to_type()
9// } else {9 } else {
10// Some(Type::Void)10 Some(Type::Void)
11// }11 }
12// }12 }
13// ExprData::Binary { op, left, right } => {13 ExprData::Binary { op, left, right } => {
14// // TODO: this likely has to do further type checking14 // TODO: this likely has to do further type checking
15// let left_type = left.to_type();15 let left_type = left.to_type();
16// match op {16 match op {
17// BinaryOperator::Add => left_type,17 BinaryOperator::Add => left_type,
18// BinaryOperator::Sub => left_type,18 BinaryOperator::Sub => left_type,
19// BinaryOperator::Mul => left_type,19 BinaryOperator::Mul => left_type,
20// BinaryOperator::Div => left_type,20 BinaryOperator::Div => left_type,
21// BinaryOperator::Pow => left_type,21 BinaryOperator::Pow => left_type,
22// BinaryOperator::Eq => Some(Type::Bool),22 BinaryOperator::Eq => Some(Type::Bool),
23// BinaryOperator::Gt => Some(Type::Bool),23 BinaryOperator::Gt => Some(Type::Bool),
24// BinaryOperator::Lt => Some(Type::Bool),24 BinaryOperator::Lt => Some(Type::Bool),
25// BinaryOperator::Gte => Some(Type::Bool),25 BinaryOperator::Gte => Some(Type::Bool),
26// BinaryOperator::Lte => Some(Type::Bool),26 BinaryOperator::Lte => Some(Type::Bool),
27// BinaryOperator::Lshift => Some(Type::Int),27 BinaryOperator::Lshift => Some(Type::Int),
28// BinaryOperator::Rshift => Some(Type::Int),28 BinaryOperator::Rshift => Some(Type::Int),
29// BinaryOperator::BitAnd => Some(Type::Int),29 BinaryOperator::BitAnd => Some(Type::Int),
30// BinaryOperator::BitOr => Some(Type::Int),30 BinaryOperator::BitOr => Some(Type::Int),
31// BinaryOperator::BitXor => Some(Type::Int),31 BinaryOperator::BitXor => Some(Type::Int),
32// BinaryOperator::Mod => Some(Type::Int),32 BinaryOperator::Mod => Some(Type::Int),
33// BinaryOperator::NotEq => Some(Type::Int),33 BinaryOperator::NotEq => Some(Type::Int),
3434
35// BinaryOperator::And => Some(Type::Bool),35 BinaryOperator::And => Some(Type::Bool),
36// BinaryOperator::Or => Some(Type::Bool),36 BinaryOperator::Or => Some(Type::Bool),
37// }37 }
38// }38 }
39// ExprData::Unary { op, value } => todo!(),39 ExprData::Unary { op, value } => todo!(),
40// ExprData::Function {40 ExprData::Function {
41// name,41 name,
42// params,42 params,
43// return_type,43 return_type,
44// block,44 block,
45// } => Some(return_type),45 } => Some(return_type),
46// ExprData::Call { base, arguments } => None, // oh shit. yeah this trait isn't implementable46 ExprData::Call { base, arguments } => None, // oh shit. yeah this trait isn't implementable
47// ExprData::Builtin { id, arguments } => todo!(),47 ExprData::Builtin { id, arguments } => todo!(),
48// ExprData::If(_) => todo!(),48 ExprData::If(_) => todo!(),
49// ExprData::Return(_) => todo!(),49 ExprData::Return(_) => todo!(),
50// ExprData::Literal(_) => todo!(),50 ExprData::Literal(_) => todo!(),
51// ExprData::Identifier(_) => todo!(),51 ExprData::Identifier(_) => todo!(),
52// }52 }
53// }53 }
54// }54}
crates/sema/sema_scope.rs created
crates/tokenizer/tokenizer.rs+1-1
...@@ -79,7 +79,7 @@ pub enum Token {...@@ -79,7 +79,7 @@ pub enum Token {
79impl Token {79impl Token {
80 pub fn is_start_of_statement_like_expression(&self) -> bool {80 pub fn is_start_of_statement_like_expression(&self) -> bool {
81 match &self {81 match &self {
82 Token::If | Token::OpenBrace | Token::Fn => false,82 Token::If | Token::OpenBrace => false,
83 _ => true,83 _ => true,
84 }84 }
85 }85 }