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 {
186186}
187187
188188impl Statement {
189 pub fn is_expression(&self) -> bool {
190 match &self {
191 Statement::Expr(_) => true,
192 _ => false,
193 }
194 }
195
196189 pub fn to_top_level(self) -> TopLevelStatement {
197190 match self {
198191 Statement::Expr(expr) => TopLevelStatement::Expr(expr),
......@@ -201,18 +194,22 @@ impl Statement {
201194 }
202195 }
203196
204 pub fn is_comment(&self) -> bool {
205 match self {
206 Statement::Comment(_) => true,
197 /// This is stupid function im sorry
198 pub fn require_semicolon(&self, semicolon_hint: bool) -> bool {
199 match &self {
200 Statement::Expr(_) => !semicolon_hint,
201 Statement::Decl(_) => true,
207202 _ => false,
208203 }
209204 }
210205}
211206
212207impl 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 {
214210 match &self {
215 TopLevelStatement::Expr(_) => true,
211 TopLevelStatement::Expr(_) => !earlier_hint,
212 TopLevelStatement::Decl(_) => true,
216213 _ => false,
217214 }
218215 }
......@@ -224,11 +221,4 @@ impl TopLevelStatement {
224221 TopLevelStatement::Comment(comment) => Statement::Comment(comment),
225222 }
226223 }
227
228 pub fn is_comment(&self) -> bool {
229 match self {
230 TopLevelStatement::Comment(_) => true,
231 _ => false,
232 }
233 }
234224}
crates/js_ast/hoist.rs+61-37
......@@ -2,6 +2,7 @@ use std::collections::{HashMap, HashSet};
22use std::vec;
33
44use ast::{BinaryOperator, BlockOrIf, BlockWithLoc, Expr, Statement};
5use has_side_effects::HasSideEffects;
56use tokenizer::Loc;
67
78use crate::*;
......@@ -156,9 +157,7 @@ impl HoistContext {
156157 pub fn process_statement(&mut self, statement: Statement) -> Option<()> {
157158 if statement.is_valid_js_expression() {
158159 let result = convert_valid_statement(self, statement);
159 if !result.is_literal() {
160 self.add_statement(result);
161 }
160 self.add_statement(result);
162161 return Some(());
163162 }
164163
......@@ -189,13 +188,11 @@ impl HoistContext {
189188 Statement::Expr(expr) => {
190189 if let Some(expr) = self.hoist_expression_contents(expr) {
191190 let loc = expr.loc.clone();
192 if !expr.is_literal() {
193 self.add_statement(JsStatement::new(
194 JsStatementData::Expression(expr),
195 loc,
196 None,
197 ))
198 }
191 self.add_statement(JsStatement::new(
192 JsStatementData::Expression(expr),
193 loc,
194 None,
195 ));
199196 Some(())
200197 } else {
201198 None
......@@ -209,9 +206,9 @@ impl HoistContext {
209206 /// and returns an identifier expression for it.
210207 pub fn hoist_expression_to_temporary(&mut self, expr: Expr) -> Option<JsExpr> {
211208 // TODO
212 // if !expr.has_side_effects() {
213 // return Some(self.hoist_expression_contents(expr)?);
214 // }
209 if !expr.has_side_effects() {
210 return Some(self.hoist_expression_contents(expr)?);
211 }
215212
216213 let init = self.hoist_expression_contents(expr)?;
217214
......@@ -334,7 +331,7 @@ impl HoistContext {
334331 let mut did_assign = false;
335332
336333 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
339336 self.add_statement(JsStatement::new(
340337 JsStatementData::If(js_if),
......@@ -396,7 +393,7 @@ impl HoistContext {
396393 b: BlockWithLoc,
397394 temporary: &String,
398395 did_assign: &mut bool,
399 ) -> Option<JsBlock> {
396 ) -> JsBlock {
400397 let loc = b.loc.clone();
401398
402399 // A non-block will become a block with a single expression:
......@@ -405,21 +402,22 @@ impl HoistContext {
405402 // We will also apply this transformation to blocks that are valid
406403 // expressions, because that is more concise.
407404 if b.is_valid_js_expression() {
408 return Some(JsBlock::new(
405 return JsBlock::new(
409406 vec![new_js_assignment_statement(
410407 convert_valid_block(self, b),
411408 temporary.clone(),
412409 loc.clone(),
413410 )],
414411 loc,
415 ));
412 );
416413 }
417414
418415 let mut child = self.new_child();
419416
420417 for statement in b.block.statements {
421418 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);
423421 };
424422 }
425423
......@@ -449,7 +447,9 @@ impl HoistContext {
449447 _ => {}
450448 }
451449
452 Some(JsBlock::new(child.statements, loc))
450 tree_shake_statement_list(&mut child.statements);
451
452 JsBlock::new(child.statements, loc)
453453 }
454454
455455 pub fn hoist_block_to_arrow_fn_body(&mut self, b: BlockWithLoc) -> JsArrowBody {
......@@ -494,6 +494,8 @@ impl HoistContext {
494494 _ => {}
495495 }
496496
497 tree_shake_statement_list(&mut child.statements);
498
497499 JsArrowBody::Block(JsBlock::new(child.statements, loc))
498500 }
499501
......@@ -513,16 +515,9 @@ impl HoistContext {
513515 // to assign to the temporary variable.
514516 match self.last_statement().map(|x| &x.data) {
515517 Some(JsStatementData::Expression(_)) if b.block.has_implicit_return => {
516 let last = self.statements.pop().unwrap();
517 match last {
518 JsStatement {
519 data: JsStatementData::Expression(expr),
520 ..
521 } => expr,
522 _ => {
523 self.statements.push(last);
524 JsExpr::new(JsExprData::Null, loc.clone(), None)
525 }
518 match self.statements.pop().unwrap().data {
519 JsStatementData::Expression(expr) => expr,
520 _ => unreachable!(),
526521 }
527522 }
528523 _ => JsExpr::new(JsExprData::Null, loc.clone(), None),
......@@ -536,15 +531,15 @@ impl HoistContext {
536531 condition: JsExpr,
537532 did_assign: &mut bool,
538533 temporary: &TempId,
539 ) -> Option<JsIf> {
540 let yes = self.hoist_block_to_js_block(yes, &temporary.get(&self), did_assign)?;
534 ) -> JsIf {
535 let yes = self.hoist_block_to_js_block(yes, &temporary.get(&self), did_assign);
541536
542537 let no = match no {
543538 Some(BlockOrIf::Block(no)) => Some(JsElse::Block(self.hoist_block_to_js_block(
544539 no,
545540 &temporary.get(&self),
546541 did_assign,
547 )?)),
542 ))),
548543 Some(BlockOrIf::If(else_if)) => {
549544 // If the condition of this block has a side effect, we need to
550545 // emit a block so that we can assign to the temporary variable.
......@@ -558,11 +553,12 @@ impl HoistContext {
558553 condition,
559554 did_assign,
560555 temporary,
561 )?)))
556 ))))
562557 } else {
563558 let mut temp_block = self.new_child();
564 let condition =
565 temp_block.hoist_expression_to_temporary(*else_if.condition.clone())?;
559 let condition = temp_block
560 .hoist_expression_to_temporary(*else_if.condition.clone())
561 .unwrap();
566562
567563 temp_block.add_statement(JsStatement::new(
568564 JsStatementData::If(self.hoist_js_if(
......@@ -571,11 +567,13 @@ impl HoistContext {
571567 condition,
572568 did_assign,
573569 temporary,
574 )?),
570 )),
575571 Loc::EMPTY,
576572 None,
577573 ));
578574
575 tree_shake_statement_list(&mut temp_block.statements);
576
579577 Some(JsElse::Block(JsBlock::new(
580578 temp_block.statements,
581579 Loc::EMPTY,
......@@ -585,7 +583,7 @@ impl HoistContext {
585583 None => None,
586584 };
587585
588 Some(JsIf { condition, yes, no })
586 JsIf { condition, yes, no }
589587 }
590588}
591589
......@@ -612,3 +610,29 @@ pub fn new_js_assignment_expr(expr: JsExpr, target: String, loc: Loc) -> JsExpr
612610 None,
613611 )
614612}
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 {
176176 pub fn new(data: JsStatementData, loc: Loc, comment: Option<Comment>) -> Self {
177177 Self { data, loc, comment }
178178 }
179
180 pub(crate) fn is_literal(&self) -> bool {
181 match &self.data {
182 JsStatementData::Expression(expr) => expr.is_literal(),
183 _ => false,
184 }
185 }
186179}
187180
188181#[derive(Debug, PartialEq, Clone)]
crates/parser/parse_block.rs+2-8
......@@ -46,10 +46,7 @@ pub fn parse_block(p: &mut Parser) -> Result<Block> {
4646 },
4747 Some(Token::ClosedBrace) => {
4848 p.next();
49 if !statement.is_expression()
50 && !statement.is_comment()
51 && is_statement_like_expression
52 {
49 if statement.require_semicolon(is_statement_like_expression) {
5350 p.is_top_level = was_top_level;
5451 return Err(p
5552 .error("Expected semicolon or '}' after statement".to_string())
......@@ -63,10 +60,7 @@ pub fn parse_block(p: &mut Parser) -> Result<Block> {
6360 });
6461 }
6562 _ => {
66 if !statement.is_expression()
67 && !statement.is_comment()
68 && is_statement_like_expression
69 {
63 if statement.require_semicolon(is_statement_like_expression) {
7064 p.is_top_level = was_top_level;
7165 return Err(p
7266 .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> {
2424 }
2525 }
2626 _ => {
27 if !statement.is_comment() && is_statement_like_expression {
27 if statement.require_semicolon(is_statement_like_expression) {
2828 return Err(p
2929 .error("Expected semicolon after statement".to_string())
3030 .into());
crates/sema/ast_type_coersion.rs+51-51
......@@ -1,54 +1,54 @@
11// use ast::{BinaryOperator, ExprData, Type};
22
3// impl TypeCoerceable for ExprData {
4// fn to_type(&self) -> Option<Type> {
5// match self {
6// ExprData::Block(block) => {
7// if (block.has_implicit_return) {
8// block.statements.last().unwrap().to_type()
9// } else {
10// Some(Type::Void)
11// }
12// }
13// ExprData::Binary { op, left, right } => {
14// // TODO: this likely has to do further type checking
15// let left_type = left.to_type();
16// match op {
17// BinaryOperator::Add => left_type,
18// BinaryOperator::Sub => left_type,
19// BinaryOperator::Mul => left_type,
20// BinaryOperator::Div => left_type,
21// BinaryOperator::Pow => left_type,
22// BinaryOperator::Eq => Some(Type::Bool),
23// BinaryOperator::Gt => Some(Type::Bool),
24// BinaryOperator::Lt => Some(Type::Bool),
25// BinaryOperator::Gte => Some(Type::Bool),
26// BinaryOperator::Lte => Some(Type::Bool),
27// BinaryOperator::Lshift => Some(Type::Int),
28// BinaryOperator::Rshift => Some(Type::Int),
29// BinaryOperator::BitAnd => Some(Type::Int),
30// BinaryOperator::BitOr => Some(Type::Int),
31// BinaryOperator::BitXor => Some(Type::Int),
32// BinaryOperator::Mod => Some(Type::Int),
33// BinaryOperator::NotEq => Some(Type::Int),
3impl TypeCoerceable for ExprData {
4 fn to_type(&self) -> Option<Type> {
5 match self {
6 ExprData::Block(block) => {
7 if (block.has_implicit_return) {
8 block.statements.last().unwrap().to_type()
9 } else {
10 Some(Type::Void)
11 }
12 }
13 ExprData::Binary { op, left, right } => {
14 // TODO: this likely has to do further type checking
15 let left_type = left.to_type();
16 match op {
17 BinaryOperator::Add => left_type,
18 BinaryOperator::Sub => left_type,
19 BinaryOperator::Mul => left_type,
20 BinaryOperator::Div => left_type,
21 BinaryOperator::Pow => left_type,
22 BinaryOperator::Eq => Some(Type::Bool),
23 BinaryOperator::Gt => Some(Type::Bool),
24 BinaryOperator::Lt => Some(Type::Bool),
25 BinaryOperator::Gte => Some(Type::Bool),
26 BinaryOperator::Lte => Some(Type::Bool),
27 BinaryOperator::Lshift => Some(Type::Int),
28 BinaryOperator::Rshift => Some(Type::Int),
29 BinaryOperator::BitAnd => Some(Type::Int),
30 BinaryOperator::BitOr => Some(Type::Int),
31 BinaryOperator::BitXor => Some(Type::Int),
32 BinaryOperator::Mod => Some(Type::Int),
33 BinaryOperator::NotEq => Some(Type::Int),
3434
35// BinaryOperator::And => Some(Type::Bool),
36// BinaryOperator::Or => Some(Type::Bool),
37// }
38// }
39// ExprData::Unary { op, value } => todo!(),
40// ExprData::Function {
41// name,
42// params,
43// return_type,
44// block,
45// } => Some(return_type),
46// ExprData::Call { base, arguments } => None, // oh shit. yeah this trait isn't implementable
47// ExprData::Builtin { id, arguments } => todo!(),
48// ExprData::If(_) => todo!(),
49// ExprData::Return(_) => todo!(),
50// ExprData::Literal(_) => todo!(),
51// ExprData::Identifier(_) => todo!(),
52// }
53// }
54// }
35 BinaryOperator::And => Some(Type::Bool),
36 BinaryOperator::Or => Some(Type::Bool),
37 }
38 }
39 ExprData::Unary { op, value } => todo!(),
40 ExprData::Function {
41 name,
42 params,
43 return_type,
44 block,
45 } => Some(return_type),
46 ExprData::Call { base, arguments } => None, // oh shit. yeah this trait isn't implementable
47 ExprData::Builtin { id, arguments } => todo!(),
48 ExprData::If(_) => todo!(),
49 ExprData::Return(_) => todo!(),
50 ExprData::Literal(_) => todo!(),
51 ExprData::Identifier(_) => todo!(),
52 }
53 }
54}
crates/sema/sema_scope.rs created
crates/tokenizer/tokenizer.rs+1-1
......@@ -79,7 +79,7 @@ pub enum Token {
7979impl Token {
8080 pub fn is_start_of_statement_like_expression(&self) -> bool {
8181 match &self {
82 Token::If | Token::OpenBrace | Token::Fn => false,
82 Token::If | Token::OpenBrace => false,
8383 _ => true,
8484 }
8585 }