Quellcode durchsuchen

Shorthand notation for adding new dimensions, closes #42

David Peter vor 2 Jahren
Ursprung
Commit
3c4d93af1b

+ 4 - 0
Cargo.lock

@@ -533,6 +533,9 @@ name = "heck"
 version = "0.4.1"
 version = "0.4.1"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "95505c38b4572b2d910cecb0281560f54b440a19336cbbcb27bf6ce6adc6f5a8"
 checksum = "95505c38b4572b2d910cecb0281560f54b440a19336cbbcb27bf6ce6adc6f5a8"
+dependencies = [
+ "unicode-segmentation",
+]
 
 
 [[package]]
 [[package]]
 name = "hermit-abi"
 name = "hermit-abi"
@@ -871,6 +874,7 @@ dependencies = [
  "approx",
  "approx",
  "codespan-reporting",
  "codespan-reporting",
  "glob",
  "glob",
+ "heck",
  "itertools",
  "itertools",
  "num-integer",
  "num-integer",
  "num-rational",
  "num-rational",

+ 0 - 5
Cargo.toml

@@ -10,8 +10,3 @@ members = [
 exclude = [
 exclude = [
     "numbat-wasm"
     "numbat-wasm"
 ]
 ]
-
-[profile.release]
-lto = true
-strip = true
-codegen-units = 1

+ 1 - 2
examples/custom_dimensions.nbt

@@ -1,5 +1,4 @@
-dimension Student
-unit student: Student
+unit student
 
 
 let lunch_cost = 85 €
 let lunch_cost = 85 €
 
 

+ 2 - 5
examples/typecheck_error/can_not_add_apples_to_oranges.nbt

@@ -1,7 +1,4 @@
-dimension Apple
-unit apple: Apple
-
-dimension Orange
-unit orange: Orange
+unit apple
+unit orange
 
 
 apple + orange
 apple + orange

+ 1 - 0
numbat/Cargo.toml

@@ -20,6 +20,7 @@ codespan-reporting = "0.11"
 strsim = "0.10.0"
 strsim = "0.10.0"
 pretty_dtoa = "0.3"
 pretty_dtoa = "0.3"
 numbat-exchange-rates = { version = "0.1.0", path = "../numbat-exchange-rates" }
 numbat-exchange-rates = { version = "0.1.0", path = "../numbat-exchange-rates" }
+heck = { version = "0.4.1", features = ["unicode"] }
 
 
 [dev-dependencies]
 [dev-dependencies]
 approx = "0.5"
 approx = "0.5"

+ 7 - 5
numbat/src/ast.rs

@@ -379,7 +379,7 @@ pub enum Statement {
         return_type_annotation: Option<DimensionExpression>,
         return_type_annotation: Option<DimensionExpression>,
     },
     },
     DeclareDimension(String, Vec<DimensionExpression>),
     DeclareDimension(String, Vec<DimensionExpression>),
-    DeclareBaseUnit(Span, String, DimensionExpression, Vec<Decorator>),
+    DeclareBaseUnit(Span, String, Option<DimensionExpression>, Vec<Decorator>),
     DeclareDerivedUnit {
     DeclareDerivedUnit {
         identifier_span: Span,
         identifier_span: Span,
         identifier: String,
         identifier: String,
@@ -550,9 +550,11 @@ impl PrettyPrint for Statement {
                     + m::keyword("unit")
                     + m::keyword("unit")
                     + m::space()
                     + m::space()
                     + m::unit(identifier)
                     + m::unit(identifier)
-                    + m::operator(":")
-                    + m::space()
-                    + dexpr.pretty_print()
+                    + if let Some(dexpr) = dexpr {
+                        m::operator(":") + m::space() + dexpr.pretty_print()
+                    } else {
+                        Markup::default()
+                    }
             }
             }
             Statement::DeclareDerivedUnit {
             Statement::DeclareDerivedUnit {
                 identifier_span: _,
                 identifier_span: _,
@@ -726,7 +728,7 @@ impl ReplaceSpans for Statement {
             Statement::DeclareBaseUnit(_, name, type_, decorators) => Statement::DeclareBaseUnit(
             Statement::DeclareBaseUnit(_, name, type_, decorators) => Statement::DeclareBaseUnit(
                 Span::dummy(),
                 Span::dummy(),
                 name.clone(),
                 name.clone(),
-                type_.replace_spans(),
+                type_.as_ref().map(|t| t.replace_spans()),
                 decorators.clone(),
                 decorators.clone(),
             ),
             ),
             Statement::DeclareDerivedUnit {
             Statement::DeclareDerivedUnit {

+ 12 - 1
numbat/src/parser.rs

@@ -468,7 +468,14 @@ impl<'a> Parser<'a> {
                     Ok(Statement::DeclareBaseUnit(
                     Ok(Statement::DeclareBaseUnit(
                         identifier_span,
                         identifier_span,
                         unit_name,
                         unit_name,
-                        dexpr,
+                        Some(dexpr),
+                        decorators,
+                    ))
+                } else if self.is_end_of_statement() {
+                    Ok(Statement::DeclareBaseUnit(
+                        identifier_span,
+                        unit_name,
+                        None,
                         decorators,
                         decorators,
                     ))
                     ))
                 } else {
                 } else {
@@ -995,6 +1002,10 @@ impl<'a> Parser<'a> {
         self.tokens.get(self.current - 1)
         self.tokens.get(self.current - 1)
     }
     }
 
 
+    pub fn is_end_of_statement(&self) -> bool {
+        self.peek().kind == TokenKind::Newline || self.is_at_end()
+    }
+
     pub fn is_at_end(&self) -> bool {
     pub fn is_at_end(&self) -> bool {
         self.peek().kind == TokenKind::Eof
         self.peek().kind == TokenKind::Eof
     }
     }

+ 13 - 4
numbat/src/typechecker.rs

@@ -466,10 +466,19 @@ impl TypeChecker {
                 )
                 )
             }
             }
             ast::Statement::DeclareBaseUnit(_span, unit_name, dexpr, decorators) => {
             ast::Statement::DeclareBaseUnit(_span, unit_name, dexpr, decorators) => {
-                let type_specified = self
-                    .registry
-                    .get_base_representation(&dexpr)
-                    .map_err(TypeCheckError::RegistryError)?;
+                let type_specified = if let Some(dexpr) = dexpr {
+                    self.registry
+                        .get_base_representation(&dexpr)
+                        .map_err(TypeCheckError::RegistryError)?
+                } else {
+                    use heck::ToUpperCamelCase;
+                    // In a unit definition like 'unit pixel' without a specified type,
+                    // we add a new type for the user
+                    let type_name = unit_name.to_upper_camel_case();
+                    self.registry
+                        .add_base_dimension(&type_name)
+                        .map_err(TypeCheckError::RegistryError)?
+                };
                 for (name, _) in decorator::name_and_aliases(&unit_name, &decorators) {
                 for (name, _) in decorator::name_and_aliases(&unit_name, &decorators) {
                     self.identifiers
                     self.identifiers
                         .insert(name.clone(), type_specified.clone());
                         .insert(name.clone(), type_specified.clone());