From 4b606ddde48d77e17516373af8dc852df3b26651 Mon Sep 17 00:00:00 2001 From: NeilBrown Date: Mon, 13 May 2019 16:17:12 +1000 Subject: [PATCH] oceani: add the option for "const" sections These are introduced with "const" and can define one or more constants - on one line with ';' or multiple lines with {} or : Signed-off-by: NeilBrown --- csrc/oceani-tests.mdc | 56 ++++++++++++++++++++++++++++++ csrc/oceani.mdc | 79 +++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 135 insertions(+) diff --git a/csrc/oceani-tests.mdc b/csrc/oceani-tests.mdc index a41b199..10a3b70 100644 --- a/csrc/oceani-tests.mdc +++ b/csrc/oceani-tests.mdc @@ -131,6 +131,29 @@ Next we change the value of variables ###### output: setvar 1.07374e+09 1 +Now some contants + +###### test list + oceani_tests += "consts" + +###### test: consts + const: + pi ::= 3.1415926 + four ::= 2 + 2 ; five ::= 10/2 + const pie ::= "I like Pie"; + cake ::= "The cake is" + ++ " a lie" + + program: + print "Hello World, what lovely oceans you have!" + print "are there", five, "?" + print pi, pie, "but", cake + +###### output: consts + Hello World, what lovely oceans you have! + are there 5 ? + 3.14159 I like Pie but The cake is a lie + ## Conditions and Loops Now we need to test if/else and some different loops @@ -646,6 +669,39 @@ various places that `type_err()` are called. .tmp.code:3:14: info: this is where 'b' was set to label oceani: type error in program - not running. +###### test list + oceani_failing_tests += type_err_const type_err_const1 + +###### test: type_err_const + const: + foo :: number = 45 + bar ::= "string" + 56 + const: + bar ::= "baz" + program: + foo := 4 + print foo, bar + +###### output: type_err_const + .tmp.code:4:16: error: expected number found string + .tmp.code:6:8: error: name already declared: bar + .tmp.code:4:8: info: this is where 'bar' was first declared + .tmp.code:8:8: error: variable 'foo' redeclared + .tmp.code:3:8: info: this is where 'foo' was first declared + +###### test: type_err_const1 + const: + foo : number = 45 + bar := "string" + program: + foo := 4 + print foo, bar + +###### output: type_err_const1 + .tmp.code:3:12: error: unhandled parse error: : + oceani: no program found. + + ## Test erroneous command line args To improve coverage, we want to test correct handling of strange command diff --git a/csrc/oceani.mdc b/csrc/oceani.mdc index 48ce058..58d5d32 100644 --- a/csrc/oceani.mdc +++ b/csrc/oceani.mdc @@ -1081,6 +1081,8 @@ no longer be primary. v = t->previous; free_value(t->val); + if (t->min_depth == 0) + free_exec(t->where_decl); free(t); } } @@ -3574,6 +3576,73 @@ various declarations in the parse context. ## top level grammar +### The `const` section + +As well as being defined in with the code that uses them, constants +can be declared at the top level. These have full-file scope, so they +are always `InScope`. The value of a top level constant can be given +as an expression, and this is evaluated immediately rather than in the +later interpretation stage. Once we add functions to the language, we +will need rules concern which, if any, can be used to define a top +level constant. + +Constants are defined in a sectiont that starts with the reserved word +`const` and then has a block with a list of assignment statements. +For syntactic consistency, these must use the double-colon syntax to +make it clear that they are constants. Type can also be given: if +not, the type will be determined during analysis, as with other +constants. + +###### top level grammar + + DeclareConstant -> const Open ConstList Close + | const Open Newlines ConstList Close + | const Open SimpleConstList } + | const Open Newlines SimpleConstList } + | const : ConstList + | const SimpleConstList + + ConstList -> ComplexConsts + ComplexConsts -> ComplexConst ComplexConsts + | ComplexConst + ComplexConst -> SimpleConstList NEWLINE + SimpleConstList -> Const ; SimpleConstList + | Const + | Const ; SimpleConstList ; + + $*type + CType -> Type ${ $0 = $<1; }$ + | ${ $0 = NULL; }$ + $void + Const -> IDENTIFIER :: CType = Expression ${ { + int ok; + struct variable *v; + + v = var_decl(config2context(config), $1.txt); + if (v) { + struct var *var = new_pos(var, $1); + v->where_decl = var; + v->where_set = var; + var->var = v; + v->constant = 1; + } else { + v = var_ref(config2context(config), $1.txt); + tok_err(config2context(config), "error: name already declared", &$1); + type_err(config2context(config), "info: this is where '%v' was first declared", + v->where_decl, NULL, 0, NULL); + } + do { + ok = 1; + propagate_types($5, config2context(config), &ok, $3, 0); + } while (ok == 2); + if (!ok) + config2context(config)->parse_error = 1; + else if (v) { + v->val = interp_exec($5); + } + } }$ + + ### Finally the whole program. Somewhat reminiscent of Pascal a (current) Ocean program starts with @@ -3735,8 +3804,18 @@ Fibonacci, and performs a binary search for a number. ###### test: hello + const: + pi ::= 3.1415926 + four ::= 2 + 2 ; five ::= 10/2 + const pie ::= "I like Pie"; + cake ::= "The cake is" + ++ " a lie" + program A B: print "Hello World, what lovely oceans you have!" + print "are there", five, "?" + print pi, pie, "but", cake + /* When a variable is defined in both branches of an 'if', * and used afterwards, the variables are merged. */ -- 2.43.0