Browse Source

some new spans + some new functions

Getty Ritter 1 year ago
parent
commit
c39e01115c
3 changed files with 112 additions and 28 deletions
  1. 36 7
      examples/person.matzo
  2. 72 17
      src/builtins.rs
  3. 4 4
      src/interp.rs

+ 36 - 7
examples/person.matzo

@@ -2,7 +2,7 @@ gender:= Male | Female | Unspec;
 byGender := { [m,f,n] => { [Male] => m; [Female] => f; [_] => n }};
 
 ending  := byGender["o","a","e"];
-pronoun := byGender["He","She","They"];
+pronoun := byGender["he","she","they"];
 noun    := byGender["man","woman","person"];
 are     := byGender["is","is","are"];
 have    := byGender["has", "has", "have"];
@@ -22,6 +22,7 @@ job := { [g] =>
   | case g in
       { Male   => "fisherman"
       ; Female => "fisherwoman"
+      ; _      => "fisher"
       } };
 tool := { ["stonemason"] => "chisel"
         ; ["baker"]      => "bowl"
@@ -34,10 +35,38 @@ adjective ::= happy cheerful focused quiet meek rash;
 person :=
   let fix my-gender := gender in {
   let fix my-job := job[my-gender] in {
-    "You come across " str/capitalize[name[my-gender]] ", a " noun[my-gender]
-      " from the city of " str/capitalize[name[Female]] ". "
-      pronoun[my-gender] " " are[my-gender] " a hardworking " my-job " with "
-      hairColor " hair and " eyeColor " eyes. "
-      str/capitalize[pronoun[my-gender]] " "
-      have[my-gender] " a " tool[my-job] " and " are[my-gender] " very " adjective "." } };
+    se[
+      "You come across",
+      str/capitalize[name[my-gender]],
+      ", a",
+      noun[my-gender],
+      "from the city of",
+      str/capitalize[name[Female]]
+      "."
+    ]
+    " "
+    se[
+      pronoun[my-gender],
+      are[my-gender],
+      "a hardworking",
+      my-job,
+      "with",
+      hairColor,
+      "hair and",
+      eyeColor,
+      "eyes."
+    ]
+    " "
+    se[
+      pronoun[my-gender],
+      have[my-gender],
+      "a",
+      tool[my-job],
+      "and",
+      are[my-gender],
+      "very",
+      adjective,
+      "."
+    ]
+  } };
 puts person;

+ 72 - 17
src/builtins.rs

@@ -32,7 +32,11 @@ pub fn builtins() -> Vec<BuiltinFunc> {
                         let mut buf = String::new();
                         let num = state.eval(*rep, env)?.as_num(&state.ast.borrow())?;
                         for _ in 0..num {
-                            buf.push_str(state.eval(*expr, env)?.as_str(&state.ast.borrow())?);
+                            buf.push_str(
+                                state
+                                    .eval(*expr, env)?
+                                    .as_str(&state.ast.borrow(), expr.span)?,
+                            );
                         }
                         Ok(Value::Lit(Literal::Str(buf)))
                     } else {
@@ -48,7 +52,7 @@ pub fn builtins() -> Vec<BuiltinFunc> {
                     if let [expr] = exprs {
                         let s = state.eval(*expr, env)?;
                         Ok(Value::Lit(Literal::Str(
-                            s.as_str(&state.ast.borrow())?.to_uppercase(),
+                            s.as_str(&state.ast.borrow(), expr.span)?.to_uppercase(),
                         )))
                     } else {
                         arity_error("str/upper", 1, exprs)
@@ -63,7 +67,7 @@ pub fn builtins() -> Vec<BuiltinFunc> {
                     if let [expr] = exprs {
                         let s = state.eval(*expr, env)?;
                         Ok(Value::Lit(Literal::Str(titlecase::titlecase(
-                            s.as_str(&state.ast.borrow())?,
+                            s.as_str(&state.ast.borrow(), expr.span)?,
                         ))))
                     } else {
                         arity_error("str/capitalize", 1, exprs)
@@ -78,7 +82,7 @@ pub fn builtins() -> Vec<BuiltinFunc> {
                     if let [expr] = exprs {
                         let s = state.eval(*expr, env)?;
                         Ok(Value::Lit(Literal::Str(
-                            s.as_str(&state.ast.borrow())?.to_lowercase(),
+                            s.as_str(&state.ast.borrow(), expr.span)?.to_lowercase(),
                         )))
                     } else {
                         arity_error("str/lower", 1, exprs)
@@ -86,6 +90,54 @@ pub fn builtins() -> Vec<BuiltinFunc> {
                 },
             ),
         },
+        BuiltinFunc {
+            name: "wd",
+            callback: Box::new(
+                |state: &State, exprs: &[ExprRef], env: &Env| -> Result<Value, MatzoError> {
+                    let mut buf = String::new();
+                    for expr in exprs {
+                        let s = state.eval(*expr, env)?;
+                        buf.push_str(s.as_str(&state.ast.borrow(), expr.span)?);
+                    }
+                    Ok(Value::Lit(Literal::Str(buf)))
+                },
+            ),
+        },
+        BuiltinFunc {
+            name: "se",
+            callback: Box::new(
+                |state: &State, exprs: &[ExprRef], env: &Env| -> Result<Value, MatzoError> {
+                    let mut buf = String::new();
+                    let mut capitalized = false;
+                    let mut last_char = '\0';
+                    for expr in exprs.iter() {
+                        let s = state.eval(*expr, env)?;
+                        let s = s.as_str(&state.ast.borrow(), expr.span)?;
+                        if !capitalized && !s.trim().is_empty() {
+                            capitalized = true;
+                            let mut chars = s.chars();
+                            for c in chars.next().unwrap().to_uppercase() {
+                                buf.push(c);
+                            }
+                            for c in chars {
+                                buf.push(c);
+                            }
+                        } else if last_char.is_alphanumeric()
+                            && s.chars().next().map_or(false, |c| c.is_alphanumeric())
+                        {
+                            buf.push(' ');
+                            buf.push_str(s.trim());
+                        } else {
+                            buf.push_str(s.trim());
+                        }
+                        if buf.len() > 0 {
+                            last_char = buf.chars().last().unwrap();
+                        }
+                    }
+                    Ok(Value::Lit(Literal::Str(buf)))
+                },
+            ),
+        },
         BuiltinFunc {
             name: "add",
             callback: Box::new(
@@ -135,7 +187,7 @@ pub fn builtins() -> Vec<BuiltinFunc> {
                     if let [expr] = exprs {
                         let tup = state.eval(*expr, env)?;
                         Ok(Value::Lit(Literal::Num(
-                            tup.as_tup(&state.ast.borrow())?.len() as i64,
+                            tup.as_tup(&state.ast.borrow(), expr.span)?.len() as i64,
                         )))
                     } else {
                         arity_error("tuple/len", 1, exprs)
@@ -149,10 +201,13 @@ pub fn builtins() -> Vec<BuiltinFunc> {
                 |state: &State, exprs: &[ExprRef], env: &Env| -> Result<Value, MatzoError> {
                     if let [expr] = exprs {
                         let val = state.eval(*expr, env)?;
-                        let tup = val.as_tup(&state.ast.borrow())?;
+                        let tup = val.as_tup(&state.ast.borrow(), expr.span)?;
                         let mut contents = Vec::new();
                         for elem in tup {
-                            for th in state.hnf(elem)?.as_tup(&state.ast.borrow())? {
+                            for th in state
+                                .hnf(elem)?
+                                .as_tup(&state.ast.borrow(), Span::empty())?
+                            {
                                 contents.push(th.clone());
                             }
                         }
@@ -167,11 +222,11 @@ pub fn builtins() -> Vec<BuiltinFunc> {
             name: "tuple/index",
             callback: Box::new(
                 |state: &State, exprs: &[ExprRef], env: &Env| -> Result<Value, MatzoError> {
-                    if let [tup, idx] = exprs {
-                        let tup = state.eval(*tup, env)?;
+                    if let [tup_e, idx] = exprs {
+                        let tup = state.eval(*tup_e, env)?;
                         let idx = state.eval(*idx, env)?;
                         state.hnf(
-                            &tup.as_tup(&state.ast.borrow())?
+                            &tup.as_tup(&state.ast.borrow(), tup_e.span)?
                                 [idx.as_num(&state.ast.borrow())? as usize],
                         )
                     } else {
@@ -186,7 +241,7 @@ pub fn builtins() -> Vec<BuiltinFunc> {
                 |state: &State, exprs: &[ExprRef], env: &Env| -> Result<Value, MatzoError> {
                     if let [tup, idx, new] = exprs {
                         let tup_val = state.eval(*tup, env)?;
-                        let tup = tup_val.as_tup(&state.ast.borrow())?;
+                        let tup = tup_val.as_tup(&state.ast.borrow(), tup.span)?;
                         let idx = state.eval(*idx, env)?.as_num(&state.ast.borrow())?;
 
                         let mut modified = Vec::with_capacity(tup.len());
@@ -208,12 +263,12 @@ pub fn builtins() -> Vec<BuiltinFunc> {
             name: "tuple/fold",
             callback: Box::new(
                 |state: &State, exprs: &[ExprRef], env: &Env| -> Result<Value, MatzoError> {
-                    if let [func, init, tup] = exprs {
+                    if let [func, init, tup_e] = exprs {
                         let func = state.eval(*func, env)?;
-                        let tup = state.eval(*tup, env)?;
+                        let tup = state.eval(*tup_e, env)?;
 
                         let mut result = Thunk::Expr(*init, env.clone());
-                        for t in tup.as_tup(&state.ast.borrow())? {
+                        for t in tup.as_tup(&state.ast.borrow(), tup_e.span)? {
                             result = Thunk::Value(state.eval_closure(
                                 func.as_closure(&state.ast.borrow())?,
                                 vec![result, t.clone()],
@@ -231,13 +286,13 @@ pub fn builtins() -> Vec<BuiltinFunc> {
             name: "tuple/map",
             callback: Box::new(
                 |state: &State, exprs: &[ExprRef], env: &Env| -> Result<Value, MatzoError> {
-                    if let [func, tup] = exprs {
+                    if let [func, tup_e] = exprs {
                         let func = state.eval(*func, env)?;
-                        let tup = state.eval(*tup, env)?;
+                        let tup = state.eval(*tup_e, env)?;
 
                         let mut new_tup = Vec::new();
                         let closure = func.as_closure(&state.ast.borrow())?;
-                        for t in tup.as_tup(&state.ast.borrow())? {
+                        for t in tup.as_tup(&state.ast.borrow(), tup_e.span)? {
                             new_tup
                                 .push(Thunk::Value(state.eval_closure(closure, vec![t.clone()])?));
                         }

+ 4 - 4
src/interp.rs

@@ -48,21 +48,21 @@ impl Value {
     }
 
     /// Convert this value to a Rust string, failing otherwise
-    pub fn as_str(&self, ast: &ASTArena) -> Result<&str, MatzoError> {
+    pub fn as_str(&self, ast: &ASTArena, span: Span) -> Result<&str, MatzoError> {
         match self {
             Value::Lit(Literal::Str(s)) => Ok(s),
             _ => self.with_str(ast, |s| {
-                return Err(MatzoError::no_loc(format!("Expected string, got {}", s)));
+                return Err(MatzoError::new(span, format!("Expected string, got {}", s)));
             }),
         }
     }
 
     /// Convert this value to a Rust slice, failing otherwise
-    pub fn as_tup(&self, ast: &ASTArena) -> Result<&[Thunk], MatzoError> {
+    pub fn as_tup(&self, ast: &ASTArena, span: Span) -> Result<&[Thunk], MatzoError> {
         match self {
             Value::Tup(vals) => Ok(vals),
             _ => self.with_str(ast, |s| {
-                return Err(MatzoError::no_loc(format!("Expected tuple, got {}", s)));
+                return Err(MatzoError::new(span, format!("Expected tuple, got {}", s)));
             }),
         }
     }