Skip to content

Commit 506be8b

Browse files
authored
Change lexing arrangement (#191)
Lots of changes to how lexing is done. Should fix some issues, make the parsing simpler and faster
1 parent 96d5058 commit 506be8b

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

73 files changed

+6049
-8255
lines changed

.github/workflows/performance-and-size.yml

+7-12
Original file line numberDiff line numberDiff line change
@@ -206,24 +206,19 @@ jobs:
206206
shell: bash
207207
continue-on-error: true
208208
run: |
209-
strings=(
210-
"https://esm.sh/v128/react-dom@18.2.0/es2022/react-dom.mjs"
211-
"https://esm.sh/v135/typescript@5.3.3/es2022/typescript.mjs"
212-
)
213-
214-
for url in "${strings[@]}"; do
215-
# TODO copy expression
216-
curl -sS $url > input.js
209+
CORPUS_URL="https://gist.githubusercontent.com/kaleidawave/6708f604bc403021b56cb54ea50cac62/raw/javascript_files.txt"
217210
211+
curl -s "$CORPUS_URL" | while IFS= read -r URL; do
212+
FILENAME="${URL##*/}"
213+
curl -s "$URL" > $FILENAME
218214
echo "::group::Comparison"
219-
hyperfine -i \
220-
-L compiler ${{ steps.compilers.outputs.BINARIES }} \
221-
'{compiler} ast-explorer full input.js --timings'
215+
hyperfine -i -L compiler ${{ steps.compilers.outputs.BINARIES }} \
216+
'{compiler} ast-explorer full $FILENAME --check'
222217
echo "::endgroup::"
223218
done
224219
225220
- name: Upload checker
226-
if: github.ref == 'main'
221+
if: ${{ github.ref_name == 'main' }}
227222
uses: actions/upload-artifact@v4
228223
with:
229224
name: latest-checker

.github/workflows/rust.yml

+12-5
Original file line numberDiff line numberDiff line change
@@ -84,13 +84,20 @@ jobs:
8484
- 'checker/**'
8585
8686
- name: Run parser tests
87+
if: steps.changes.outputs.parser == 'true' || github.ref_name == 'main'
88+
run: cargo test --no-fail-fast
89+
working-directory: parser
90+
91+
- name: Run parser examples
8792
if: steps.changes.outputs.parser == 'true' || github.ref_name == 'main'
8893
run: |
89-
cargo test
90-
91-
# TODO more
92-
curl https://esm.sh/v128/react-dom@18.2.0/es2022/react-dom.mjs > react.js
93-
cargo run -p ezno-parser --example parse react.js
94+
CORPUS_URL="https://gist.githubusercontent.com/kaleidawave/6708f604bc403021b56cb54ea50cac62/raw/javascript_files.txt"
95+
96+
curl -s "$CORPUS_URL" | while IFS= read -r URL; do
97+
FILENAME="${URL##*/}"
98+
curl -s "$URL" > $FILENAME
99+
cargo run -p ezno-parser --example parse $FILENAME
100+
done
94101
working-directory: parser
95102

96103
- name: Run checker specification

Cargo.lock

-12
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

Cargo.toml

+2-3
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,6 @@ members = [
99
# "lsp/server",
1010
]
1111

12-
1312
[package]
1413
name = "ezno"
1514
description = "A fast and correct TypeScript type checker and compiler with additional experiments. For use as a library or through the CLI"
@@ -100,5 +99,5 @@ result_unit_err = "allow"
10099
thread_local_initializer_can_be_made_const = "allow"
101100
implicit_hasher = "allow"
102101

103-
[profile.dev]
104-
debug = false
102+
# [profile.dev]
103+
# debug = false

checker/src/context/environment.rs

+2-2
Original file line numberDiff line numberDiff line change
@@ -80,8 +80,8 @@ impl DynamicBoundaryKind {
8080
}
8181

8282
impl ContextType for Syntax<'_> {
83-
fn as_general_context(et: &Context<Self>) -> GeneralContext<'_> {
84-
GeneralContext::Syntax(et)
83+
fn as_general_context(context: &Context<Self>) -> GeneralContext<'_> {
84+
GeneralContext::Syntax(context)
8585
}
8686

8787
fn get_parent(&self) -> Option<&GeneralContext<'_>> {

checker/src/features/constant_functions.rs

+2-2
Original file line numberDiff line numberDiff line change
@@ -678,9 +678,9 @@ pub(crate) fn call_constant_function(
678678
return Err(ConstantFunctionError::CannotComputeConstant);
679679
};
680680

681-
Some(flags.clone())
681+
flags.clone()
682682
}
683-
None => None,
683+
None => String::new(),
684684
};
685685

686686
let regexp = types.new_regexp(&pattern.clone(), &flags, &call_site.without_source());

checker/src/features/regexp.rs

+16-24
Original file line numberDiff line numberDiff line change
@@ -21,36 +21,31 @@ pub struct RegExp {
2121
}
2222

2323
impl RegExp {
24-
pub fn new(pattern: &str, flag_options: Option<&str>) -> Result<Self, String> {
25-
let source = if let Some(flag_options) = flag_options {
26-
format!("/{pattern}/{flag_options}")
27-
} else {
28-
format!("/{pattern}/")
29-
};
30-
24+
pub fn new(pattern: &str, flag_options: &str) -> Result<Self, String> {
25+
let source = format!("/{pattern}/{flag_options}");
3126
let mut flags = Flags::default();
3227
let mut flags_unsupported = false;
3328

34-
if let Some(flag_options) = flag_options {
35-
for flag in flag_options.chars() {
36-
#[allow(clippy::match_same_arms)]
37-
match flag {
38-
'd' => flags_unsupported = true, // indices for substring matches are not supported
39-
'g' => flags_unsupported = true, // stateful regex is not supported
40-
'i' => flags.icase = true,
41-
'm' => flags.multiline = true,
42-
's' => flags.dot_all = true,
43-
'u' => flags.unicode = true,
44-
'v' => flags.unicode_sets = true,
45-
'y' => flags_unsupported = true, // sticky search is not supported
46-
_ => panic!("Unknown flag: {flag:?}"),
47-
}
29+
for flag in flag_options.chars() {
30+
#[allow(clippy::match_same_arms)]
31+
match flag {
32+
'd' => flags_unsupported = true, // indices for substring matches are not supported
33+
'g' => flags_unsupported = true, // stateful regex is not supported
34+
'i' => flags.icase = true,
35+
'm' => flags.multiline = true,
36+
's' => flags.dot_all = true,
37+
'u' => flags.unicode = true,
38+
'v' => flags.unicode_sets = true,
39+
'y' => flags_unsupported = true, // sticky search is not supported
40+
// Should be caught by parser errors
41+
_ => panic!("Unknown flag: {flag:?}"),
4842
}
4943
}
5044

5145
let compiled_regex = {
5246
let mut ire = backends::try_parse(pattern.chars().map(u32::from), flags)
5347
.map_err(|err| err.text)?;
48+
5449
if !flags.no_opt {
5550
backends::optimize(&mut ire);
5651
}
@@ -314,10 +309,7 @@ impl BinarySerializable for RegExp {
314309

315310
fn deserialize<I: Iterator<Item = u8>>(iter: &mut I, source_id: SourceId) -> Self {
316311
let source = String::deserialize(iter, source_id);
317-
318312
let (pattern, flags) = source[1..].rsplit_once('/').unwrap();
319-
let flags = if flags.is_empty() { None } else { Some(flags) };
320-
321313
Self::new(pattern, flags).unwrap()
322314
}
323315
}

checker/src/synthesis/assignments.rs

+11-7
Original file line numberDiff line numberDiff line change
@@ -162,13 +162,13 @@ fn synthesise_array_to_reference<
162162
default_value.clone(),
163163
)
164164
}
165-
parser::ArrayDestructuringField::Comment { content, is_multiline, position } => {
166-
AssignableArrayDestructuringField::Comment {
167-
content: content.clone(),
168-
is_multiline: *is_multiline,
169-
position: position.with_source(environment.get_source()),
170-
}
171-
}
165+
// parser::ArrayDestructuringField::Comment { content, is_multiline, position } => {
166+
// AssignableArrayDestructuringField::Comment {
167+
// content: content.clone(),
168+
// is_multiline: *is_multiline,
169+
// position: position.with_source(environment.get_source()),
170+
// }
171+
// }
172172
parser::ArrayDestructuringField::None => AssignableArrayDestructuringField::None,
173173
})
174174
.collect(),
@@ -269,5 +269,9 @@ pub(crate) fn synthesise_access_to_reference<T: crate::ReadFromFS>(
269269
publicity: crate::types::properties::Publicity::Public,
270270
}
271271
}
272+
VariableOrPropertyAccess::NonNullAssertion(on, _) => {
273+
// TODO
274+
synthesise_access_to_reference(on, environment, checking_data)
275+
}
272276
}
273277
}

checker/src/synthesis/declarations.rs

+32-20
Original file line numberDiff line numberDiff line change
@@ -93,11 +93,15 @@ pub(crate) fn synthesise_declaration<T: crate::ReadFromFS>(
9393
}
9494
}
9595
}
96+
parser::declarations::export::Exportable::VarStatement(_) => {
97+
todo!()
98+
}
9699
parser::declarations::export::Exportable::ImportAll { .. }
97100
| parser::declarations::export::Exportable::ImportParts { .. }
98101
| parser::declarations::export::Exportable::Function(_)
99102
| parser::declarations::export::Exportable::EnumDeclaration(_)
100103
| parser::declarations::export::Exportable::Interface(_)
104+
| parser::declarations::export::Exportable::Namespace(_)
101105
| parser::declarations::export::Exportable::TypeAlias(_) => {}
102106
}
103107
}
@@ -124,7 +128,10 @@ pub(crate) fn synthesise_declaration<T: crate::ReadFromFS>(
124128
);
125129
}
126130
}
127-
parser::declarations::ExportDeclaration::DefaultFunction { position, .. } => {
131+
parser::declarations::ExportDeclaration::TSDefaultFunctionDeclaration {
132+
position,
133+
..
134+
} => {
128135
checking_data.diagnostics_container.add_error(
129136
TypeCheckError::FunctionWithoutBodyNotAllowedHere {
130137
position: position.with_source(environment.get_source()),
@@ -147,28 +154,33 @@ pub(crate) fn synthesise_declaration<T: crate::ReadFromFS>(
147154

148155
// TODO remove enumerate, add add function and more
149156
for (idx, member) in r#enum.on.members.iter().enumerate() {
150-
match member {
151-
parser::ast::EnumMember::Variant { name, value, position } => {
152-
if let Some(ref _value) = value {
153-
checking_data.raise_unimplemented_error(
154-
"enum with value",
155-
position.with_source(environment.get_source()),
156-
);
157-
}
158-
159-
let value = checking_data
160-
.types
161-
.new_constant_type(Constant::Number((idx as u8).into()));
162-
163-
basis.append(
164-
Publicity::Public,
165-
PropertyKey::from(name.clone()),
166-
PropertyValue::Value(value),
167-
member.get_position().with_source(environment.get_source()),
168-
&mut environment.info,
157+
let parser::ast::EnumMember { name, value, position } = member;
158+
match value {
159+
parser::ast::EnumMemberValue::ClassMembers(_) => {
160+
checking_data.raise_unimplemented_error(
161+
"class enums",
162+
position.with_source(environment.get_source()),
169163
);
170164
}
165+
parser::ast::EnumMemberValue::Value(_) => {
166+
checking_data.raise_unimplemented_error(
167+
"enum with value",
168+
position.with_source(environment.get_source()),
169+
);
170+
}
171+
parser::ast::EnumMemberValue::None => {}
171172
}
173+
174+
let value =
175+
checking_data.types.new_constant_type(Constant::Number((idx as u8).into()));
176+
177+
basis.append(
178+
Publicity::Public,
179+
PropertyKey::from(name.clone()),
180+
PropertyValue::Value(value),
181+
member.get_position().with_source(environment.get_source()),
182+
&mut environment.info,
183+
);
172184
}
173185

174186
let variable = crate::VariableId(environment.get_source(), r#enum.get_position().start);

checker/src/synthesis/expressions.rs

+4-2
Original file line numberDiff line numberDiff line change
@@ -969,13 +969,15 @@ pub(super) fn synthesise_expression<T: crate::ReadFromFS>(
969969
let location = function.header.get_location().map(|location| match location {
970970
parser::functions::FunctionLocationModifier::Server => "server".to_owned(),
971971
parser::functions::FunctionLocationModifier::Worker => "worker".to_owned(),
972+
parser::functions::FunctionLocationModifier::Test => "test".to_owned(),
972973
});
974+
let name = function.name.as_option_str().map(ToOwned::to_owned);
973975
Instance::RValue(register_expression_function(
974976
expecting,
975977
is_async,
976978
is_generator,
977979
location,
978-
function.name.as_option_str().map(ToOwned::to_owned),
980+
name,
979981
function,
980982
environment,
981983
checking_data,
@@ -989,7 +991,7 @@ pub(super) fn synthesise_expression<T: crate::ReadFromFS>(
989991
Expression::Comment { on, .. } => {
990992
return synthesise_expression(on, environment, checking_data, expecting);
991993
}
992-
Expression::ParenthesizedExpression(inner_expression, _) => Instance::RValue(
994+
Expression::Parenthesised(inner_expression, _) => Instance::RValue(
993995
synthesise_multiple_expression(inner_expression, environment, checking_data, expecting),
994996
),
995997
Expression::ClassExpression(class) => Instance::RValue(synthesise_class_declaration(

checker/src/synthesis/extensions/jsx.rs

+3-3
Original file line numberDiff line numberDiff line change
@@ -105,7 +105,7 @@ pub(crate) fn synthesise_jsx_element<T: crate::ReadFromFS>(
105105
// attribute_name: match attribute {
106106
// JSXAttribute::Static(name, _, _)
107107
// | JSXAttribute::Dynamic(name, _, _)
108-
// | JSXAttribute::BooleanAttribute(name, _) => name.clone(),
108+
// | JSXAttribute::Boolean(name, _) => name.clone(),
109109
// JSXAttribute::Spread(_, _) => todo!(),
110110
// JSXAttribute::Shorthand(_) => todo!(),
111111
// },
@@ -327,7 +327,7 @@ pub(crate) fn synthesise_jsx_element<T: crate::ReadFromFS>(
327327
// // attribute_name: match attribute {
328328
// // JSXAttribute::Static(name, _, _)
329329
// // | JSXAttribute::Dynamic(name, _, _)
330-
// // | JSXAttribute::BooleanAttribute(name, _) => name.clone(),
330+
// // | JSXAttribute::Boolean(name, _) => name.clone(),
331331
// // JSXAttribute::Spread(_, _) => todo!(),
332332
// // JSXAttribute::Shorthand(_) => todo!(),
333333
// // },
@@ -497,7 +497,7 @@ fn synthesise_attribute<T: crate::ReadFromFS>(
497497
// TODO expecting
498498
(name, synthesise_expression(expression, environment, checking_data, TypeId::ANY_TYPE))
499499
}
500-
JSXAttribute::BooleanAttribute(name, _) => (name, TypeId::TRUE),
500+
JSXAttribute::Boolean(name, _) => (name, TypeId::TRUE),
501501
JSXAttribute::Spread(_, pos) => {
502502
checking_data.raise_unimplemented_error(
503503
"spread JSX attribute",

checker/src/synthesis/functions.rs

+1-2
Original file line numberDiff line numberDiff line change
@@ -513,8 +513,7 @@ pub(super) fn variable_field_to_string(param: &VariableField) -> String {
513513
parser::ArrayDestructuringField::Name(name, ..) => {
514514
buf.push_str(&variable_field_to_string(name));
515515
}
516-
parser::ArrayDestructuringField::Comment { .. }
517-
| parser::ArrayDestructuringField::None => {}
516+
parser::ArrayDestructuringField::None => {}
518517
}
519518
if not_at_end {
520519
buf.push_str(", ");

0 commit comments

Comments
 (0)