diff --git a/asteroid/grammar.txt b/asteroid/grammar.txt index 9dbc5b71..9e3ee119 100644 --- a/asteroid/grammar.txt +++ b/asteroid/grammar.txt @@ -1,16 +1,21 @@ -/************************************************************************************** - Grammar for Asteroid written in EBNF/PEG format. - (c) University of Rhode Island - - Notes: - - We generate documentation directly from this grammar file. In order to - be properly formatted in the target documentation please respect the - indentation given below. - - Use C++ style comments for any comments that you DO want to be displayed - in the target documentation. - - C style comments for any comments that you DO NOT want to be displayed - in the target documentation -- like the one you are reading right now... - **************************************************************************************/ + +#define NOTE(x) + + NOTE(" + ************************************************************************************** + Grammar for Asteroid written in EBNF/PEG format. + (c) University of Rhode Island + + Notes: + - We generate documentation directly from this grammar file. In order to + be properly formatted in the target documentation please respect the + indentation given below. + - Use C++ style comments for any comments that you DO want to be displayed + in the target documentation. + - Use the NOTE macro for any comments that you DO NOT want to be displayed + in the target documentation -- like the one you are reading right now... + ************************************************************************************** + ") //////////////////////////////////////////////////////////////////////////////////////// // statements @@ -61,28 +66,27 @@ //////////////////////////////////////////////////////////////////////////////////////// // expressions/patterns - /* - NOTE: There is no syntactic difference between a pattern - and an expression. We introduce the 'pattern' nonterminal - to highlight the SEMANTIC difference between patterns and - expressions. - */ + NOTE(" + There is no syntactic difference between a pattern and an expression. We introduce + the 'pattern' nonterminal to highlight the SEMANTIC difference between patterns and + expressions. + ") exp : pattern pattern : PATTERN WITH? exp - | '%[' exp ']%' binding_list? /* constraint-only pattern match */ + | '%[' exp ']%' binding_list? NOTE(" constraint-only pattern match ") | head_tail head_tail : conditional ('|' exp)? - /* - conditional patterns are now supported via 'pattern if cond' - no else part. Since this overlaps with conditional expressions - we check for correct usage semantically. - */ + NOTE(" + conditional patterns are now supported via 'pattern if cond' + no else part. Since this overlaps with conditional expressions + we check for correct usage semantically. + ") conditional : compound (IF exp (ELSE exp)?)? @@ -90,8 +94,8 @@ : logic_exp0 ( (IS pattern) | - (IN exp) | /* exp has to be a list */ - (TO exp (STEP exp)?) | /* list comprehension */ + (IN exp) | NOTE(" exp has to be a list ") + (TO exp (STEP exp)?) | NOTE(" list comprehension ") )? logic_exp0 @@ -113,7 +117,7 @@ : call_or_index (('*' | '/') call_or_index)* call_or_index - : primary (primary | '@' primary)* (':' pattern)? /* named pattern when ': pattern' exists */ + : primary (primary | '@' primary)* (':' pattern)? NOTE(" conditional pattern when ': pattern' exists ") //////////////////////////////////////////////////////////////////////////////////////// // primary expressions/patterns @@ -126,16 +130,16 @@ | FALSE | NONE | ID - | '*' call_or_index binding_list? /* pattern dereferencing */ + | '*' call_or_index binding_list? NOTE(" pattern dereferencing ") | NOT call_or_index | MINUS call_or_index | PLUS call_or_index - | '(' tuple_stuff ')' /* tuple/parenthesized expr */ - | '[' list_stuff ']' /* list or list access */ + | '(' tuple_stuff ')' NOTE(" tuple/parenthesized expr ") + | '[' list_stuff ']' NOTE(" list or list access ") | function_const | TYPEMATCH // TYPEMATCH == '%' -/* Note: binding lists are only supported for constraint patterns */ +NOTE(" Note: binding lists are only supported for constraint patterns ") binding_list : BIND binding_list_suffix diff --git a/asteroid/modules/math.ast b/asteroid/modules/math.ast index 3a469039..5580def5 100644 --- a/asteroid/modules/math.ast +++ b/asteroid/modules/math.ast @@ -13,6 +13,7 @@ ------------------------------------------------------------------ let pi = escape "from math import pi;global __retval__;__retval__=('real',pi)" +let tau = escape "from math import tau;global __retval__;__retval__=('real',tau)" let e = escape "from math import e;global __retval__;__retval__=('real',e)" ------------------------------------------------------------------ @@ -97,10 +98,201 @@ __retval__ = ('real',sqrt(val_a[1])) " end +------------------------------------------------------------------ +function isqrt +------------------------------------------------------------------ +-- Return the integer square root of the nonnegative integer n. +-- This is the floor of the exact square root of n, or the greatest +-- integer a such that a^2 <= n. +with a do return escape +" +global __retval__ +from asteroid.state import state +from math import isqrt + +val_a = state.symbol_table.lookup_sym('a') +if val_a[0] not in ['integer','real']: + raise ValueError('unsupported type \'{}\' for isqrt'.format(val_a[0])) +__retval__ = ('integer',isqrt(val_a[1])) +" +end + +------------------------------------------------------------------ +function ldexp +------------------------------------------------------------------ +-- Return x * (2**i) +with (x,i) do return escape +" +global __retval__ +from math import ldexp + +val_x = state.symbol_table.lookup_sym('x') +val_i = state.symbol_table.lookup_sym('i') + +if val_x[0] not in ['integer','real'] or val_i[0] not in ['integer','real']: + raise ValueError('unsupported type for ldexp') +__retval__ = ('real',ldexp(val_x[1],val_i[1])) +" +end + +------------------------------------------------------------------ +function expm1 +------------------------------------------------------------------ +-- Return e raised to the power x, minus 1. +with x do return escape +" +global __retval__ +from math import expm1 + +val_x = state.symbol_table.lookup_sym('x') + +if val_x[0] not in ['integer','real']: + raise ValueError('unsupported type for expm1') +__retval__ = ('real',expm1(val_x[1])) +" +end + +------------------------------------------------------------------ +function log1p +------------------------------------------------------------------ +-- Return the natural logarithm of 1+x (base e). +with x do return escape +" +global __retval__ +from math import log1p + +val_x = state.symbol_table.lookup_sym('x') + +if val_x[0] not in ['integer','real']: + raise ValueError('unsupported type for log1p') +__retval__ = ('real',log1p(val_x[1])) +" +end + +------------------------------------------------------------------ +function log2 +------------------------------------------------------------------ +-- Return the base-2 logarithm of x. +with x do return escape +" +global __retval__ +from math import log2 + +val_x = state.symbol_table.lookup_sym('x') + +if val_x[0] not in ['integer','real']: + raise ValueError('unsupported type for log2') +__retval__ = ('real',log2(val_x[1])) +" +end + +------------------------------------------------------------------ +function log10 +------------------------------------------------------------------ +-- Return the base-10 logarithm of x. +with x do return escape +" +global __retval__ +from math import log10 + +val_x = state.symbol_table.lookup_sym('x') + +if val_x[0] not in ['integer','real']: + raise ValueError('unsupported type for log10') +__retval__ = ('real',log10(val_x[1])) +" +end + ------------------------------------------------------------------ -- Number-theoretic and representation functions ------------------------------------------------------------------ +------------------------------------------------------------------ +function prod +------------------------------------------------------------------ +-- Returns the product of a list or tuple +-- conditional pattern match asserts the the input is a list or +-- tuple and that every element is a real or integer value. This +-- is to avoid strings getting in and having Python's definition +-- of multiplication between ints and strings applied. +with x if ((x is %list) or (x is %tuple)) + do return escape +" +global __retval__ +from math import prod + +val_x = state.symbol_table.lookup_sym('x') + +if val_x[0] not in ['list','tuple'] : + raise ValueError('unsupported type for prod') + +__val__ = prod( to_python_list(val_x) ) + +if isinstance(__val__,float): + __retval__ = ('real',__val__) +else: + __retval__ = ('integer',__val__) +" +end + +------------------------------------------------------------------ +function sum +------------------------------------------------------------------ +-- Returns the sum of a list or tuple +with x do return escape +" +global __retval__ + +val_x = state.symbol_table.lookup_sym('x') + +if val_x[0] not in ['list','tuple'] : + raise ValueError('unsupported type for sum') + +__val__ = sum( to_python_list(val_x) ) + +if isinstance(__val__,float): + __retval__ = ('real',__val__) +else: + __retval__ = ('integer',__val__) +" +end + +------------------------------------------------------------------ +function fsum +------------------------------------------------------------------ +-- Returns the sum of a list or tuple. Returns an accurate +-- floating point sum of values in the iterable. Avoids loss of +-- precision by tracking multiple intermediate partial sums. +with x do return escape +" +global __retval__ +from math import fsum + +val_x = state.symbol_table.lookup_sym('x') + +if val_x[0] not in ['list','tuple'] : + raise ValueError('unsupported types for fsum') + +__retval__ = ('real',fsum( to_python_list(val_x) )) + +" +end + +------------------------------------------------------------------ +function remainder +------------------------------------------------------------------ +with (a,b) do return escape +" +global __retval__ +from math import remainder + +val_a = state.symbol_table.lookup_sym('a') +val_b = state.symbol_table.lookup_sym('b') + +__retval__ = ('real', remainder(val_a[1], val_b[1])) +" +end + ------------------------------------------------------------------ function abs ------------------------------------------------------------------ @@ -173,11 +365,74 @@ from math import gcd val_a = state.symbol_table.lookup_sym('a') val_b = state.symbol_table.lookup_sym('b') - __retval__ = ('integer', gcd(val_a[1], val_b[1])) " end +------------------------------------------------------------------ +function lcm +------------------------------------------------------------------ +-- Return the least common multiple of the integer arguments. +with (a:%integer,b:%integer) do return escape +" +global __retval__ +from math import lcm + +val_a = state.symbol_table.lookup_sym('a') +val_b = state.symbol_table.lookup_sym('b') + +__retval__ = ('integer', lcm(val_a[1], val_b[1])) +" +end + +------------------------------------------------------------------ +function copysign +------------------------------------------------------------------ +-- Return a float with the absolute value of x and the sign of y. +with (x,y) do return escape +" +global __retval__ +from math import copysign + +val_x = state.symbol_table.lookup_sym('x') +val_y = state.symbol_table.lookup_sym('y') + +if val_x[0] not in ['integer','real'] or val_y[0] not in ['integer','real']: + raise ValueError('unsupported types for copysign') +__retval__ = (val_x[0], copysign(val_x[1],val_y[1])) +" +end + +------------------------------------------------------------------ +function factorial +------------------------------------------------------------------ +-- Return n factorial as an integer. +with n:%integer do return escape +" +global __retval__ +from math import factorial + +val_n = state.symbol_table.lookup_sym('n') + +__retval__ = ('integer', factorial(val_n[1])) +" +end + +------------------------------------------------------------------ +function trunc +------------------------------------------------------------------ +-- Return n with its fractional component set to 0. +with n:%real do return escape +" +global __retval__ +from math import trunc + +val_n = state.symbol_table.lookup_sym('n') + +__retval__ = ('integer', trunc(val_n[1])) +" +end + ------------------------------------------------------------------ function isclose ------------------------------------------------------------------ @@ -225,6 +480,29 @@ raise ValueError('unsupported type in \'mod\'') " end +------------------------------------------------------------------ +function fmod +------------------------------------------------------------------ +-- Return fmod(x, y), as defined by the platform C library. The +-- intent of the C standard is that fmod(x, y) be exactly +-- (mathematically; to infinite precision) equal to x - n*y for +-- some integer n such that the result has the same sign as x +-- and magnitude less than abs(y). +with (v:%integer,d:%integer) do return escape +" +global __retval__ +from math import fmod + +val_v = state.symbol_table.lookup_sym('v') +val_d = state.symbol_table.lookup_sym('d') + +__retval__ = ('integer',fmod(val_v[1], val_d[1])) +" +with _ do escape +" +raise ValueError('unsupported type in \'fmod\'') +" +end ------------------------------------------------------------------ -- Trigonometric functions @@ -278,6 +556,23 @@ __retval__ = ('real', math.atan(x_val[1])) " end +------------------------------------------------------------------ +function atan2 +------------------------------------------------------------------ +-- Return atan(y / x), in radians. The result is between -pi and +-- pi. +with (x,y) do return escape +" +import math +global __retval__ + +x_val = state.symbol_table.lookup_sym('x') +y_val = state.symbol_table.lookup_sym('y') + +__retval__ = ('real', math.atan2(x_val[1],y_val[1])) +" +end + ------------------------------------------------------------------ function cos ------------------------------------------------------------------ @@ -413,6 +708,48 @@ __retval__ = ('real', math.tanh(x_val[1])) " end +------------------------------------------------------------------ +function dist +------------------------------------------------------------------ +-- Return the Euclidean distance between two points p and q, each +-- given as a sequence (or iterable) of coordinates. +with (x,y) do return escape +" +global __retval__ +from math import dist + +val_x = state.symbol_table.lookup_sym('x') +val_y = state.symbol_table.lookup_sym('y') + +if val_x[0] not in ['list','tuple'] or val_y[0] not in ['list','tuple']: + raise ValueError('unsupported types for dist') +if len(val_x[1]) != len(val_y[1]): + raise ValueError('points must do of same dimension for dist') + +__retval__ = ('real', dist(to_python_list(val_x),to_python_list(val_y))) +" +end + +------------------------------------------------------------------ +function hypot +------------------------------------------------------------------ +-- Return the Euclidean norm, sqrt(sum(x**2 for x in coordinates)) +with (a,b) do return escape +" +global __retval__ +from math import hypot + +val_a = state.symbol_table.lookup_sym('a') +val_b = state.symbol_table.lookup_sym('b') + +__retval__ = ('real',hypot(val_a[1],val_b[1])) +" +end + +------------------------------------------------------------------ +-- Conversions +------------------------------------------------------------------ + ------------------------------------------------------------------ function degrees ------------------------------------------------------------------ @@ -443,4 +780,108 @@ __retval__ = ('real', math.radians(x_val[1])) " end +------------------------------------------------------------------ +-- Combinatoric functions +------------------------------------------------------------------ + +------------------------------------------------------------------ +function comb +------------------------------------------------------------------ +-- Return the number of ways to choose k items from n items +-- without repetition and without order. Evaluates to +-- n! / (k! * (n - k)!) when k <= n and evaluates to zero when +-- k > n. +with (n:%integer,k:%integer) do return escape +" +global __retval__ +from math import comb + +val_n = state.symbol_table.lookup_sym('n') +val_k = state.symbol_table.lookup_sym('k') + +__retval__ = ('integer',comb(val_n[1],val_k[1])) +" +end + +------------------------------------------------------------------ +function perm +------------------------------------------------------------------ +-- Return the number of ways to choose k items from n items +-- without repetition and with order. Evaluates to +-- n! / (n - k)! when k <= n and evaluates to zero when k > n. +with (n:%integer,k:%integer) do return escape +" +global __retval__ +from math import perm + +val_n = state.symbol_table.lookup_sym('n') +val_k = state.symbol_table.lookup_sym('k') + +__retval__ = ('integer',perm(val_n[1],val_k[1])) +" +end + +------------------------------------------------------------------ +-- Special functions +------------------------------------------------------------------ + +------------------------------------------------------------------ +function erf +------------------------------------------------------------------ +-- Return the error function at x. +with x do return escape +" +global __retval__ +from math import erf + +val_x = state.symbol_table.lookup_sym('x') + +__retval__ = ('real',erf(val_x[1])) +" +end + +------------------------------------------------------------------ +function erfc +------------------------------------------------------------------ +-- Return the complementary error function at x. +with x do return escape +" +global __retval__ +from math import erfc + +val_x = state.symbol_table.lookup_sym('x') + +__retval__ = ('real',erfc(val_x[1])) +" +end + +------------------------------------------------------------------ +function gamma +------------------------------------------------------------------ +-- Return the Gamma function at x. +with x do return escape +" +global __retval__ +from math import gamma + +val_x = state.symbol_table.lookup_sym('x') + +__retval__ = ('real',gamma(val_x[1])) +" +end + +------------------------------------------------------------------ +function lgamma +------------------------------------------------------------------ +-- Return the natural logarithm of the absolute value of the Gamma +-- function at x. +with x do return escape +" +global __retval__ +from math import lgamma + +val_x = state.symbol_table.lookup_sym('x') +__retval__ = ('real',lgamma(val_x[1])) +" +end \ No newline at end of file diff --git a/asteroid/modules/patterns.ast b/asteroid/modules/patterns.ast new file mode 100644 index 00000000..e257a73f --- /dev/null +++ b/asteroid/modules/patterns.ast @@ -0,0 +1,139 @@ +------------------------------------------------------------------ +-- patterns.ast +-- +-- this module implements common patterns +-- +-- +-- (c) University of Rhode Island +------------------------------------------------------------------ +load system math. + +------------------------------------------------------------------ +-- Helper functions +------------------------------------------------------------------ +-- returns a boolean indicating if the passed in integer is prime. +function is_prime + with (n:%integer) do + if n <= 1 do + return false. + end + + if (n == 2) or (n == 3) do + return true. + end + + if (math@mod(n,2) == 0) or (math@mod(n,3) == 0) do + return false. + end + + for i in 5 to math@isqrt(n) step 6 do + if (math@mod(n,i) == 0) or (math@mod(n,i+2) == 0) do + return false. + end + end + + return true. + with _ do + return false. +end +------------------------------------------------------------------ +function is_alphabetic + with (s:%string) do return escape +" +global __retval__ + +val_s = state.symbol_table.lookup_sym('s') + +__retval__ = ('boolean',str.isalpha(val_s[1])) +" + with _ do + return false. + end +------------------------------------------------------------------ +function is_numeric + with (s:%string) do return escape +" +global __retval__ + +val_s = state.symbol_table.lookup_sym('s') + +__retval__ = ('boolean',str.isnumeric(val_s[1])) +" + with _ do + return false. + end +------------------------------------------------------------------ +function is_uppercase + with (s:%string) do return escape +" +global __retval__ + +val_s = state.symbol_table.lookup_sym('s') + +__retval__ = ('boolean',str.isupper(val_s[1])) +" + with _ do + return false. + end +------------------------------------------------------------------ +function is_lowercase + with (s:%string) do return escape +" +global __retval__ + +val_s = state.symbol_table.lookup_sym('s') + +__retval__ = ('boolean',str.islower(val_s[1])) +" + with _ do + return false. + end +------------------------------------------------------------------ +function is_alphanumeric + with (s:%string) do return escape +" +global __retval__ + +val_s = state.symbol_table.lookup_sym('s') + +__retval__ = ('boolean',str.isalnum(val_s[1])) +" + with _ do + return false. + end + +------------------------------------------------------------------ +-- Common number sets +------------------------------------------------------------------ +let prime = pattern with %[ (n:%integer) if patterns@is_prime(n) ]%. +let digit = pattern with %[ (n:%integer) if n >=0 and n <= 9 ]%. +let pos_int = pattern with %[ (n:%integer) if n > 0 ]%. +let neg_int = pattern with %[ (n:%integer) if n < 0 ]%. +let pos_real = pattern with %[ (n:%real) if n > 0.0 ]%. +let neg_real = pattern with %[ (n:%real) if n < 0.0 ]%. +let positive = pattern with %[ n if (n is *patterns@pos_int) or (n is *patterns@pos_real) ]%. +let negative = pattern with %[ n if (n is *patterns@neg_int) or (n is *patterns@neg_real) ]%. +let nat = pattern with %[ (n:%integer) if n >= 0 ]%. +let zero = pattern with %[ n if ((n is %real) and (math@isclose(toreal(n), 0.0))) + or ((n is %integer) and (tointeger(n) == 0)) ]%. +let odd = pattern with %[ (n:%integer) if math@mod(n,2) == 1 ]%. +let even = pattern with %[ (n:%integer) if math@mod(n,2) == 0 ]%. +------------------------------------------------------------------ +-- Containers +------------------------------------------------------------------ +let int_list = pattern %[(l:%list) if l @reduce (lambda with (acc,i) do (i is %integer) and acc, true)]%. +let real_list = pattern %[(l:%list) if l @reduce (lambda with (acc,i) do (i is %real) and acc, true)]%. +let str_list = pattern %[(l:%list) if l @reduce (lambda with (acc,i) do (i is %string) and acc, true)]%. +let bool_list = pattern %[(l:%list) if l @reduce (lambda with (acc,i) do (i is %boolean) and acc, true)]%. +let func_list = pattern %[(l:%list) if l @reduce (lambda with (acc,i) do (i is %function) and acc, true)]%. +let list_list = pattern %[(l:%list) if l @reduce (lambda with (acc,i) do (i is %list) and acc, true)]%. +let tuple_list = pattern %[(l:%list) if l @reduce (lambda with (acc,i) do (i is %tuple) and acc, true)]%. +------------------------------------------------------------------ +-- Strings +------------------------------------------------------------------ +let char = pattern with %[ (s:%string) if (s@length() == 1) ]%. +let alphabetic = pattern with %[ (s:%string) if patterns@is_alphabetic(s) ]%. +let numeric = pattern with %[ (s:%string) if patterns@is_numeric(s) ]%. +let alphanumeric = pattern with %[ (s:%string) if patterns@is_alphanumeric(s) ]%. +let uppercase = pattern with %[ (s:%string) if patterns@is_uppercase(s) ]%. +let lowercase = pattern with %[ (s:%string) if patterns@is_lowercase(s) ]%. \ No newline at end of file diff --git a/asteroid/support.py b/asteroid/support.py index 49214876..7401c6c3 100644 --- a/asteroid/support.py +++ b/asteroid/support.py @@ -188,6 +188,19 @@ def data_ix_list(memory): return ix_list +########################################################################################### +def to_python_list(asteroid_list): + ''' + convert a list from Asteroid list or tuple AST format into a standard Python list. + ex. ('list',[('integer',1),('integer',2)]) => [1,2] + ''' + output = [] + + for (_type,val) in asteroid_list[1]: + output.append(val) + + return output + ########################################################################################### # term2string is an unparsing function mapping AST snippets representing **values** into # a Python string diff --git a/asteroid/test-suites/ref-programs/patterns.ast b/asteroid/test-suites/ref-programs/patterns.ast new file mode 100644 index 00000000..14c27b45 --- /dev/null +++ b/asteroid/test-suites/ref-programs/patterns.ast @@ -0,0 +1,9 @@ + load system patterns. + + let evens = []. + for num in 1 to 10 do + if num is *patterns@even do + let evens = evens@append(num). + end + end + assert(evens is [2,4,6,8,10]). \ No newline at end of file diff --git a/asteroid/test-suites/regression-tests/test157.ast b/asteroid/test-suites/regression-tests/test157.ast new file mode 100644 index 00000000..ed8ccfdd --- /dev/null +++ b/asteroid/test-suites/regression-tests/test157.ast @@ -0,0 +1,514 @@ +load system io. +load system math. + +-- Math library revision test 6/18/2023 ttc + +let failures = 0. +let EXPECTED = pattern with Exception( "SystemError" , _ ). + +-- ********************** +-- **** Constants **** +-- ********************** +let x = math@ pi. +let y = math@ tau. +assert( math@isclose( (2.0*x) ,y) ). -- assert tau is correct value + +-- ********************** +-- **** Combinations **** +-- ********************** +assert( math@comb(10,7) == 120 ). +assert( math@comb(10,5) == 252 ). +assert( math@comb(7,5) == 21 ). +assert( math@comb(5,7) == 0 ). +assert( math@comb(0,7) == 0 ). + +try + math@comb(-1,7). + let failures = failures + 1. +catch *EXPECTED do + . --pass +end +try + math@comb(10.2,7). + let failures = failures + 1. +catch *EXPECTED do + . --pass +end + +-- ********************** +-- **** Permutations **** +-- ********************** +assert( math@perm(10,7) == 604800 ). +assert( math@perm(10,5) == 30240 ). +assert( math@perm(7,5) == 2520 ). +assert( math@perm(5,7) == 0 ). +assert( math@perm(0,7) == 0 ). + +try + math@perm(-1,7). + let failures = failures + 1. +catch *EXPECTED do + . --pass +end +try + math@perm(10.3,7). + let failures = failures + 1. +catch *EXPECTED do + . --pass +end + +-- ********************** +-- **** isqrt **** +-- ********************** +assert( math@isqrt(16) == 4 ). +assert( math@isqrt(17) == 4 ). +assert( math@isqrt(18) == 4 ). +assert( math@isqrt(20) == 4 ). +assert( math@isqrt(4) == 2 ). +assert( math@isqrt(5) == 2 ). +assert( math@isqrt(101) == 10 ). +assert( math@isqrt(150) == 12 ). + +try + math@isqrt(-1.1). + let failures = failures + 1. +catch *EXPECTED do + . --pass +end +try + math@isqrt("hello"). + let failures = failures + 1. +catch *EXPECTED do + . --pass +end + +-- ********************** +-- **** ldexp **** +-- ********************** +assert( math@ldexp(7,7) == 896.0 ). +assert( math@ldexp(-4,12) == -16384.0 ). +assert( math@ldexp(11,-3) == 11.0/8.0 ). +assert( math@ldexp(9,8) == 2304.0 ). + +try + mathldexp("hello",7). + let failures = failures + 1. +catch *EXPECTED do + . --pass +end +try + math@ldexp(7,"hello"). + let failures = failures + 1. +catch *EXPECTED do + . --pass +end + +-- ********************** +-- **** prod **** +-- ********************** +assert( math@prod( [1,2,3,4,5] ) == 120 ). +assert( math@prod( (1,2,3,4,5) ) == 120 ). +assert( math@prod( [-2,-2,-2,-2] ) == 16 ). +assert( math@prod( [-2,-2,-2,-2,-2] ) == -32 ). +assert( math@prod( (12.3,100.01,14.56,9.5) ) == 170150.61336 ). +assert( math@prod( [1,2,3,4,5] ) == math@prod( (5,4,3,2,1) ) ). + +try + math@prod( ["h","e","l","l","o"] ). + let failures = failures + 1. +catch *EXPECTED do + . --pass +end +try + math@prod( "hello" ). + let failures = failures + 1. +catch *EXPECTED do + . --pass +end + +-- ********************** +-- **** sum **** +-- ********************** +assert( math@sum( [1,2,3,4,5] ) == 15 ). +assert( math@sum( (1,2,3,4,5) ) == 15 ). +assert( math@sum( [-2,-2,-2,-2] ) == -8 ). +assert( math@sum( [-2,-2,-2,-2,-2] ) == -10 ). +assert( math@sum( (12.3,100.01,14.56,9.5) ) == 136.37 ). +assert( math@sum( [1,2,3,4,5] ) == math@sum( (5,4,3,2,1) ) ). + +try + math@sum( ["h","e","l","l","o"] ). + let failures = failures + 1. +catch *EXPECTED do + . --pass +end +try + math@sum( "hello" ). + let failures = failures + 1. +catch *EXPECTED do + . --pass +end +-- ********************** +-- **** fsum **** +-- ********************** +assert( math@fsum( [0.1,0.1,0.1,0.1,0.1,0.1,0.1,0.1,0.1,0.1] ) == 1.0 ). +assert( math@fsum( (1.0/5.0,1.0/5.0,1.0/5.0,1.0/5.0,1.0/5.0) ) == 1.0 ). + +try + math@fsum( ["h","e","l","l","o"] ). + let failures = failures + 1. +catch *EXPECTED do + . --pass +end +try + math@fsum( "hello" ). + let failures = failures + 1. +catch *EXPECTED do + . --pass +end +-- ********************** +-- **** lcm **** +-- ********************** +assert( math@lcm(4,5) == 20 ). +assert( math@lcm(5,4) == 20 ). +assert( math@lcm(6,8) == 24 ). +assert( math@lcm(13,17) == 221 ). +assert( math@lcm(101,117) == 11817 ). + +try + math@lcm( "a",12 ). + let failures = failures + 1. +catch *EXPECTED do + . --pass +end +try + math@lcm( 33,"b" ). + let failures = failures + 1. +catch *EXPECTED do + . --pass +end +-- ********************** +-- **** copysign **** +-- ********************** +assert( math@copysign(1.1,2.2) == 1.1 ). +assert( math@copysign(1,2) == 1 ). +assert( math@copysign(1.1,-2.2) == -1.1 ). +assert( math@copysign(1,-2) == -1 ). +assert( math@copysign(-1.1,2.2) == 1.1 ). +assert( math@copysign(-1,2) == 1 ). +assert( math@copysign(-1.1,-2.2) == -1.1 ). +assert( math@copysign(-1,-2) == -1 ). + +try + math@copysign( "a",-12 ). + let failures = failures + 1. +catch *EXPECTED do + . --pass +end +try + math@copysign( 33,"b" ). + let failures = failures + 1. +catch *EXPECTED do + . --pass +end +-- ********************** +-- **** factorial **** +-- ********************** +assert( math@factorial(1) == 1 ). +assert( math@factorial(0) == 1 ). +assert( math@factorial(10) == 3628800 ). +assert( math@factorial(5) == 120 ). +assert( math@factorial(12) == 479001600 ). +assert( math@factorial(3) == 6 ). + +try + math@copysign( 10.23 ). + let failures = failures + 1. +catch *EXPECTED do + . --pass +end +try + math@copysign( "hello" ). + let failures = failures + 1. +catch *EXPECTED do + . --pass +end +-- ********************** +-- **** trunc **** +-- ********************** +assert( math@trunc(1.00000001) == 1 ). +assert( math@trunc(1.99999999) == 1 ). +assert( math@trunc(-1.00000001) == -1 ). +assert( math@trunc(-1.99999999) == -1 ). + +try + math@trunc( 5 ). + let failures = failures + 1. +catch *EXPECTED do + . --pass +end +try + math@trunc( "hello" ). + let failures = failures + 1. +catch *EXPECTED do + . --pass +end + +-- ********************** +-- **** fmod **** +-- ********************** +assert( math@fmod(12,10) == 2 ). +assert( math@fmod(-12,10) == -2 ). +assert( math@fmod(123,5) == 3 ). +assert( math@fmod(-123,5) == -3 ). + +try + math@fmod( 5.5,100 ). + let failures = failures + 1. +catch *EXPECTED do + . --pass +end +try + math@fmod( "hello",100 ). + let failures = failures + 1. +catch *EXPECTED do + . --pass +end + +-- ********************** +-- **** atan2 **** +-- ********************** +assert( math@atan2(12,10) == 0.8760580505981934 ). +assert( math@atan2(0.5,1.666) == 0.29156692663601214 ). +assert( math@atan2(-0.9,4.001) == -0.22126091552495672 ). +assert( math@atan2(-1,-1) == -2.35619449019234484 ). + +try + math@atan2( 5.5,"hello" ). + let failures = failures + 1. +catch *EXPECTED do + . --pass +end +try + math@atan2( "hello",100 ). + let failures = failures + 1. +catch *EXPECTED do + . --pass +end + +-- ********************** +-- **** remainder **** +-- ********************** +assert( math@remainder(12,10) == 2.0 ). +assert( math@remainder(2,2) == 0.0 ). +assert( math@remainder(2,4) == 2.0 ). +assert( math@remainder(2,0.5) == 0.0 ). +assert( math@remainder(0.5,0.11) == -0.05 ). + +try + math@remainder( 5.5,"hello" ). + let failures = failures + 1. +catch *EXPECTED do + . --pass +end +try + math@remainder( "hello",100 ). + let failures = failures + 1. +catch *EXPECTED do + . --pass +end + +-- ********************** +-- **** expm1 **** +-- ********************** +assert( math@expm1(0) == 0.0 ). +assert( math@expm1(1) == 1.718281828459045 ). +assert( math@expm1(2) == 6.38905609893065 ). +assert( math@expm1(2.1) == 7.16616991256765 ). +assert( math@expm1(-1.1) == -0.6671289163019205 ). + +try + math@expm1( "hello" ). + let failures = failures + 1. +catch *EXPECTED do + . --pass +end +try + math@expm1( ["hello"] ). + let failures = failures + 1. +catch *EXPECTED do + . --pass +end + +-- ********************** +-- **** log2 **** +-- ********************** +assert( math@log2(4) == 2.0 ). +assert( math@log2(16) == 4.0 ). +assert( math@log2(1024.0) == 10.0 ). +assert( math@log2(2.1) == 1.070389327891398 ). + +try + math@log2( "hello" ). + let failures = failures + 1. +catch *EXPECTED do + . --pass +end +try + math@log2( ["hello"] ). + let failures = failures + 1. +catch *EXPECTED do + . --pass +end + +-- ********************** +-- **** log10 **** +-- ********************** +assert( math@log10(10) == 1.0 ). +assert( math@log10(100) == 2.0 ). +assert( math@log10(1000.0) == 3.0 ). +assert( math@log10(200.1) == 2.3012470886362113 ). + +try + math@log10( "hello" ). + let failures = failures + 1. +catch *EXPECTED do + . --pass +end +try + math@log10( ["hello"] ). + let failures = failures + 1. +catch *EXPECTED do + . --pass +end + +-- ********************** +-- **** dist **** +-- ********************** +assert( math@dist( (1,1) , (1,2) ) == 1.0 ). +assert( math@dist( (1,1) , (2,1) ) == 1.0 ). +assert( math@dist((2,3,4,5,6),(6,7,3,4,5)) == 5.916079783099616 ). +assert( math@dist((1,1),(100,175)) == 200.19240744843447 ). + +try + math@dist( "hello","world" ). + let failures = failures + 1. +catch *EXPECTED do + . --pass +end +try + math@dist( (1,1), (1,2,3) ). + let failures = failures + 1. +catch *EXPECTED do + . --pass +end + +-- ********************** +-- **** hypot **** +-- ********************** +assert( math@hypot( 3 , 4 ) == 5.0 ). +assert( math@hypot( 1 , 1 ) == math@sqrt(2) ). +assert( math@hypot( 5 , 5 ) == math@sqrt(50) ). +assert( math@hypot( 8 , 15 ) == 17.0 ). +assert( math@hypot( 13 , 17 ) == math@sqrt( math@pow(13,2) + math@pow(17,2)) ). + +try + math@hypot( "hello","world" ). + let failures = failures + 1. +catch *EXPECTED do + . --pass +end +try + math@hypot( [1,2,3], (1,2,3) ). + let failures = failures + 1. +catch *EXPECTED do + . --pass +end + +-- ********************** +-- **** error **** +-- ********************** +assert( math@erf( 1.1 ) == 0.8802050695740817 ). +assert( math@erf( -1.1 ) == -0.8802050695740817 ). +assert( math@erf( 10 ) == 1.0 ). +assert( math@erf( 0.13333 ) == 0.1495600366981686 ). + +try + math@erf( "hello" ). + let failures = failures + 1. +catch *EXPECTED do + . --pass +end +try + math@erf( [1,2,3] ). + let failures = failures + 1. +catch *EXPECTED do + . --pass +end + +-- ********************** +-- **** errorc **** +-- ********************** +assert( math@isclose( math@erfc( 1.1 ) , 0.11979493042591827 )). +assert( math@erfc( -1.1 ) == 1.8802050695740817 ). +assert( math@erfc( 10 ) == 2.088487583762545e-45 ). +assert( math@erfc( 0.13333 ) == 0.8504399633018314 ). + +try + math@erfc( "hello" ). + let failures = failures + 1. +catch *EXPECTED do + . --pass +end +try + math@erfc( [1,2,3] ). + let failures = failures + 1. +catch *EXPECTED do + . --pass +end + +-- ********************** +-- **** gamma **** +-- ********************** +assert( math@gamma( 1.1 ) == 0.951350769866873 ). +assert( math@gamma( -1.1 ) == 9.714806382902898 ). +assert( math@gamma( 10 ) == 362880.0 ). +assert( math@gamma( 0.13333 ) == 7.0407639878879245 ). + +try + math@gamma( "hello" ). + let failures = failures + 1. +catch *EXPECTED do + . --pass +end +try + math@gamma( [1,2,3] ). + let failures = failures + 1. +catch *EXPECTED do + . --pass +end + +-- ********************** +-- **** lgamma **** +-- ********************** +assert( math@lgamma( 1.1 ) == -0.04987244125984036 ). +assert( math@lgamma( -1.1 ) == 2.273651152924464 ). +assert( math@lgamma( 10 ) == 12.801827480081467 ). +assert( math@lgamma( 0.13333 ) == 1.9517166852887797 ). + +try + math@lgamma( "hello" ). + let failures = failures + 1. +catch *EXPECTED do + . --pass +end +try + math@lgamma( [1,2,3] ). + let failures = failures + 1. +catch *EXPECTED do + . --pass +end + +--------------------------------------------------------------- +assert( failures == 0 ). +io @println "Pass". \ No newline at end of file diff --git a/asteroid/test-suites/regression-tests/test158.ast b/asteroid/test-suites/regression-tests/test158.ast new file mode 100644 index 00000000..267fd27a --- /dev/null +++ b/asteroid/test-suites/regression-tests/test158.ast @@ -0,0 +1,589 @@ +load system io. +load system patterns. +load system math. + +-- Expirmental patterns library test + +let failures = 0. +let EXPECTED = pattern with Exception( "PatternMatchFailed" , _ ). + +-- ********************** +-- **** prime **** +-- ********************** +let x:*patterns@prime = 2. +let x:*patterns@prime = 3. +let x:*patterns@prime = 5. +let x:*patterns@prime = 11. +let x:*patterns@prime = 13. +let x:*patterns@prime = 17. +let x:*patterns@prime = 97. +let x:*patterns@prime = 83. +let x:*patterns@prime = 15485863. + +try + let x:*patterns@prime = 10. + let failures = failures + 1. +catch *EXPECTED do + . +end +try + let x:*patterns@prime = 1024. + let failures = failures + 1. +catch *EXPECTED do + . +end +try + let x:*patterns@prime = 999. + let failures = failures + 1. +catch *EXPECTED do + . +end +try + let x:*patterns@prime = 63. + let failures = failures + 1. +catch *EXPECTED do + . +end +-- ********************** +-- **** natural **** +-- ********************** +let x:*patterns@nat = 1. +let x:*patterns@nat = 2. +let x:*patterns@nat = 5. +let x:*patterns@nat = 1486987. +let x:*patterns@nat = 1010101. + +try + let x:*patterns@nat = -10. + let failures = failures + 1. +catch *EXPECTED do + . +end +try + let x:*patterns@nat = -1. + let failures = failures + 1. +catch *EXPECTED do + . +end +try + let x:*patterns@nat = 1.5. + let failures = failures + 1. +catch *EXPECTED do + . +end + +-- ********************** +-- **** pos/neg **** +-- ********************** +let x:*patterns@positive = 1. +let x:*patterns@positive = 111111111. +let x:*patterns@positive = 10. +let x:*patterns@positive = 1235.3654. + +let x:*patterns@pos_int = 12. +let x:*patterns@pos_int = 12213. +let x:*patterns@pos_int = 1. + +let x:*patterns@pos_real = 1.23. +let x:*patterns@pos_real = 15222.23. +let x:*patterns@pos_real = 0.00023. + +let x:*patterns@negative = -1. +let x:*patterns@negative = -111111111. +let x:*patterns@negative = -10. +let x:*patterns@negative = -1235.3654. + +let x:*patterns@neg_int = -12. +let x:*patterns@neg_int = -12213. +let x:*patterns@neg_int = -1. + +let x:*patterns@neg_real = -1.23. +let x:*patterns@neg_real = -15222.23. +let x:*patterns@neg_real = -0.00023. + +try + let x:*patterns@positive = -100. + let failures = failures + 1. +catch *EXPECTED do + . +end +try + let x:*patterns@positive = -0.001. + let failures = failures + 1. +catch *EXPECTED do + . +end +try + let x:*patterns@pos_int = -12. + let failures = failures + 1. +catch *EXPECTED do + . +end +try + let x:*patterns@pos_int = 1.2. + let failures = failures + 1. +catch *EXPECTED do + . +end +try + let x:*patterns@pos_real = -1.2. + let failures = failures + 1. +catch *EXPECTED do + . +end +try + let x:*patterns@pos_real = 1. + let failures = failures + 1. +catch *EXPECTED do + . +end +try + let x:*patterns@negative = 0.001. + let failures = failures + 1. +catch *EXPECTED do + . +end +try + let x:*patterns@negative = 12. + let failures = failures + 1. +catch *EXPECTED do + . +end +try + let x:*patterns@neg_int = -12.002. + let failures = failures + 1. +catch *EXPECTED do + . +end +try + let x:*patterns@neg_int = 12. + let failures = failures + 1. +catch *EXPECTED do + . +end +try + let x:*patterns@neg_real = 1.2. + let failures = failures + 1. +catch *EXPECTED do + . +end +try + let x:*patterns@neg_real = -51. + let failures = failures + 1. +catch *EXPECTED do + . +end + +-- ********************** +-- **** zero **** +-- ********************** +let x:*patterns@zero = 0. +let x:*patterns@zero = 0.0. + +try + let x:*patterns@zero = 2. + let failures = failures + 1. +catch *EXPECTED do + . +end +try + let x:*patterns@zero = 0.00000000000001. + let failures = failures + 1. +catch *EXPECTED do + . +end +try + let x:*patterns@zero = -0.2. + let failures = failures + 1. +catch *EXPECTED do + . +end +try + let x:*patterns@zero = -10. + let failures = failures + 1. +catch *EXPECTED do + . +end +-- ********************** +-- **** even/odd **** +-- ********************** +let x:*patterns@even = 2. +let x:*patterns@even = 16. +let x:*patterns@even = 2048. +let x:*patterns@odd = 1. +let x:*patterns@odd = 111117. +let x:*patterns@odd = 3. + +try + let x:*patterns@even = 1. + let failures = failures + 1. +catch *EXPECTED do + . +end +try + let x:*patterns@even = 2.01. + let failures = failures + 1. +catch *EXPECTED do + . +end +try + let x:*patterns@even = 7. + let failures = failures + 1. +catch *EXPECTED do + . +end +try + let x:*patterns@odd = 0.7. + let failures = failures + 1. +catch *EXPECTED do + . +end +try + let x:*patterns@odd = 2. + let failures = failures + 1. +catch *EXPECTED do + . +end +try + let x:*patterns@odd = 1024. + let failures = failures + 1. +catch *EXPECTED do + . +end +-- ********************** +-- **** containers **** +-- ********************** +let x:*patterns@int_list = [1,2,3,4]. +let x:*patterns@int_list = [10]. +let x:*patterns@int_list = [-1,15,32]. + +try + let x:*patterns@int_list = [1,2,3,4,5,6,7,8.2345,9,10,11,12,13,14,15]. + let failures = failures + 1. +catch *EXPECTED do + . +end +try + let x:*patterns@int_list = [1,2,3,4,"not a number",6,7,8,9,10,11,12,13,14,15]. + let failures = failures + 1. +catch *EXPECTED do + . +end +try + let x:*patterns@int_list = [ "a", "b", "c" ]. + let failures = failures + 1. +catch *EXPECTED do + . +end + +let x:*patterns@real_list = [-1.0,15.0,32.3]. +let x:*patterns@real_list = [ 1.000000001 ]. +let x:*patterns@real_list = [ 1.1 ,2.2 ,3.3 ,4.4 ,5.5 ,6.6 ,7.7 ,8.8 ,9.9 ,10.1]. + +try + let x:*patterns@real_list = [ 1.1 ,2.2 ,3.3 ,4.4 ,5 ,6.6 ,7.7 ,8.8 ,9.9 ,10.1]. + let failures = failures + 1. +catch *EXPECTED do + . +end +try + let x:*patterns@real_list = [ 1.1 ,2.2 ,3.3 ,4.4 ,"not a number" ,6.6 ,7.7 ,8.8 ,9.9 ,10.1]. + let failures = failures + 1. +catch *EXPECTED do + . +end +try + let x:*patterns@real_list = [ "a", "b", "c" ]. + let failures = failures + 1. +catch *EXPECTED do + . +end + +let x:*patterns@str_list = [ "a", "b", "c" ]. +let x:*patterns@str_list = [ "a" ]. +let x:*patterns@str_list = [ "hello", "hello", "a", "b", "c", "d", "e", "f", "g" ]. + +try + let x:*patterns@str_list = [ "a", "b", 1, "c" ]. + let failures = failures + 1. +catch *EXPECTED do + . +end +try + let x:*patterns@str_list = [ "hello", "hello", "a", "b", 1, "c", "d", "e", "f", "g" ]. + let failures = failures + 1. +catch *EXPECTED do + . +end +try + let x:*patterns@str_list = [ "hello", "hello", "a", "b", (lambda with x do true), "c", "d", "e", "f", "g" ]. + let failures = failures + 1. +catch *EXPECTED do + . +end + +let x:*patterns@bool_list = [ true, true, true, false, false, true, false, true, false, true, false, false ]. +let x:*patterns@bool_list = [ true ]. +let x:*patterns@bool_list = [ false, true, false, false ]. +let x:*patterns@bool_list = [ false ]. + +try + let x:*patterns@bool_list = [ true, true, true, false, false, 1, false, true, false, true, false, false ]. + let failures = failures + 1. +catch *EXPECTED do + . +end +try + let x:*patterns@bool_list = [ true, true, true, false, false, "false", false, true, false, true, false, false ]. + let failures = failures + 1. +catch *EXPECTED do + . +end +try + let x:*patterns@bool_list = [ true, true, true, false, false, math@pi ]. + let failures = failures + 1. +catch *EXPECTED do + . +end + +function foo1 + with _ do + true + end +function foo2 + with _ do + true + end +function foo3 + with _ do + true + end +function foo4 + with _ do + true + end +function foo5 + with _ do + true + end +function foo6 + with _ do + true + end + +let x:*patterns@func_list = [ foo1,foo2,foo3,foo4,foo5,foo6 ]. +let x:*patterns@func_list = [ patterns@is_prime ]. +let x:*patterns@func_list = [ foo1,foo2,foo3,(lambda with x do true ),foo4,foo5,foo6 ]. + +try + let x:*patterns@func_list = [ foo1,foo2,foo3,10,foo4,foo5,foo6 ]. + let failures = failures + 1. +catch *EXPECTED do + . +end +try + let x:*patterns@func_list = [ foo1,foo2,foo3,"string",foo4,foo5,foo6 ]. + let failures = failures + 1. +catch *EXPECTED do + . +end +try + let x:*patterns@func_list = [ foo1,patterns@func_list,foo4,foo5,foo6 ]. + let failures = failures + 1. +catch *EXPECTED do + . +end + +let x:*patterns@list_list = [ [1,2],[3,4],[4,5] ]. +let x:*patterns@list_list = [ [1,2],[3,4],[4,5],[6,7],[8,9,10,11] ]. +let x:*patterns@list_list = [ [1,2] ]. + +try + let x:*patterns@list_list = [ [1,2],[3,4],4,5 ]. + let failures = failures + 1. +catch *EXPECTED do + . +end +try + let x:*patterns@list_list = [ (1,2) ]. + let failures = failures + 1. +catch *EXPECTED do + . +end +try + let x:*patterns@list_list = [ 1,2,3 ]. + let failures = failures + 1. +catch *EXPECTED do + . +end + +let x:*patterns@tuple_list = [ (1,2),(3,4),(4,5) ]. +let x:*patterns@tuple_list = [ (1,2),(3,4),(4,5),(6,7),(8,9,10,11) ]. +let x:*patterns@tuple_list = [ (1,2) ]. + +try + let x:*patterns@tuple_list = [ (1,2),(3,4),4,5 ]. + let failures = failures + 1. +catch *EXPECTED do + . +end +try + let x:*patterns@tuple_list = [ [1,2] ]. + let failures = failures + 1. +catch *EXPECTED do + . +end +try + let x:*patterns@tuple_list = [ 1,2,3 ]. + let failures = failures + 1. +catch *EXPECTED do + . +end + +-- ********************** +-- **** strings **** +-- ********************** + +let x:*patterns@alphabetic = "helloworld". +let x:*patterns@alphabetic = "abcdefghijklmnopqrstuvwxyz". +let x:*patterns@alphabetic = "testingtesting". + +try + let x:*patterns@alphabetic = "hello world!". + let failures = failures + 1. +catch *EXPECTED do + . +end +try + let x:*patterns@alphabetic = "abc123". + let failures = failures + 1. +catch *EXPECTED do + . +end +try + let x:*patterns@alphabetic = "onebad$character". + let failures = failures + 1. +catch *EXPECTED do + . +end + +let x:*patterns@numeric = "123456789". +let x:*patterns@numeric = "1". +let x:*patterns@numeric = "6598942". + +try + let x:*patterns@numeric = "1234five678". + let failures = failures + 1. +catch *EXPECTED do + . +end +try + let x:*patterns@numeric = "987654321O". -- o not 0 + let failures = failures + 1. +catch *EXPECTED do + . +end +try + let x:*patterns@numeric = "1b11101". + let failures = failures + 1. +catch *EXPECTED do + . +end + +let x:*patterns@alphanumeric = "abc123". +let x:*patterns@alphanumeric = "1234five6789". +let x:*patterns@alphanumeric = "1l1l1l1". + +try + let x:*patterns@alphanumeric = "1b11101-123". + let failures = failures + 1. +catch *EXPECTED do + . +end +try + let x:*patterns@alphanumeric = "!$%^&*". + let failures = failures + 1. +catch *EXPECTED do + . +end +try + let x:*patterns@alphanumeric = "HELLO?". + let failures = failures + 1. +catch *EXPECTED do + . +end + +let x:*patterns@lowercase = "abcdefg". +let x:*patterns@lowercase = "hello". +let x:*patterns@lowercase = "z". + +try + let x:*patterns@lowercase = "HELLO". + let failures = failures + 1. +catch *EXPECTED do + . +end +try + let x:*patterns@lowercase = "abcDefg". + let failures = failures + 1. +catch *EXPECTED do + . +end +try + let x:*patterns@lowercase = "uppercaseA". + let failures = failures + 1. +catch *EXPECTED do + . +end + +let x:*patterns@uppercase = "ABCDEFGHIJKLMNOPQRSTUVWXYZ". +let x:*patterns@uppercase = "Z". +let x:*patterns@uppercase = "HELLO". + +try + let x:*patterns@uppercase = "HelloWorld". + let failures = failures + 1. +catch *EXPECTED do + . +end +try + let x:*patterns@uppercase = "a". + let failures = failures + 1. +catch *EXPECTED do + . +end +try + let x:*patterns@uppercase = "ABCDeFGHIJKLMNOPQRSTUVWXYZ". + let failures = failures + 1. +catch *EXPECTED do + . +end + +let x:*patterns@char = "a". +let x:*patterns@char = "1". +let x:*patterns@char = "?". + +try + let x:*patterns@char = "ABC". + let failures = failures + 1. +catch *EXPECTED do + . +end +try + let x:*patterns@char = "??". + let failures = failures + 1. +catch *EXPECTED do + . +end +try + let x:*patterns@char = 1. + let failures = failures + 1. +catch *EXPECTED do + . +end + + + + +assert(failures == 0). +io@println "PASS". \ No newline at end of file diff --git a/asteroid/walk.py b/asteroid/walk.py index 4b011597..ebf1bb92 100644 --- a/asteroid/walk.py +++ b/asteroid/walk.py @@ -164,6 +164,9 @@ def unify(term, pattern, unifying = True ): if pattern[1] == '_': # anonymous variable - ignore unifier return [] else: + id_val = state.symbol_table.lookup_sym(pattern[1],strict=False) + if id_val and id_val[0] == 'pattern': + warning("you are overwriting a pattern stored in '{}'".format(pattern[1])) unifier = (pattern, term) return [unifier] diff --git a/docs/Reference Guide.rst b/docs/Reference Guide.rst index 51294d95..119d66eb 100644 --- a/docs/Reference Guide.rst +++ b/docs/Reference Guide.rst @@ -727,6 +727,10 @@ are written in quotes. //////////////////////////////////////////////////////////////////////////////////////// // expressions/patterns + + + + exp : pattern @@ -739,6 +743,10 @@ are written in quotes. : conditional ('|' exp)? + + + + conditional : compound (IF exp (ELSE exp)?)? @@ -1200,6 +1208,8 @@ math **@pi** math **@e** The mathematical constant e = 2.718281…, to available precision. +math **@tau** + The mathematical constant τ = 6.283185…, to available precision. Power and logarithmic functions %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% @@ -1207,34 +1217,65 @@ Power and logarithmic functions math **@exp** x:%integer Returns e raised to the power x, where e = 2.718281… is the base of the natural logarithm. +math **@expm1** x + Returns e raised to the power x minus 1. This function maintains a higher level of precision then the standard operation. + +math **@isqrt** x:%real + Returns the floor of the square root of x as a integer. + +math **@ldexp** (x,i) + Returns x * (2^i). + math **@log** x | (x, base:%integer) If only argument x is the input, return the natural logarithm of x (to base e). If two arguments, (x, base:%integer), are given as input, return the logarithm of x to the given base, calculated as log(x)/log(base). +math **@log1p** x + Returns the natural logarithm of 1 + x. + +math **@log2** x + Returns the base 2 logarithm of x. + +math **@log10** x + Returns the base 10 logarithm of x. + math **@pow** (b, p:%integer) - Return b raised to the power p. The return type depends on the type + Returns b raised to the power p. The return type depends on the type of the base. math **@sqrt** x - Return the square root of x as a real. - + Returns the square root of x as a real. Number-theoretic and representation functions %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% math **@abs** x - Return that absolute value of x. The return type depends on the type of x. + Returns that absolute value of x. The return type depends on the type of x. math **@ceil** x:%real Returns the ceiling of x: the smallest integer greater than or equal to x. +math **@comb** (n:%integer,k:%integer) + Returns the numbers of ways to choose k items from n total items without repetition and without order. This is equal to n! / k!(n - k)!. + +math **@copysign** (x,y) + Returns a real with the absolute value of x and the sign of y. + +math **@dist** (x,y) + Return the Euclidean distance as a float between two points x and y, each given as a tuple or list of coordinates. + +math **@factorial** (n:%integer) + Returns the factorial of the integer n. + math **@floor** x:%real Returns the floor of x: the largest integer less than or equal to x. -math **@round** x:%real - Returns x rounded to the nearest integer. If two integers are equally - close, x is rounded to the nearest even integer. +math **@fmod** (v,d) + Implements the modulus operation as defined by the platform C library. This is equal to v - n*d for some integer n such that the result has the same sign as v and magnitude less than abs(d). + +math **@fsum** x:%list | x:%tuple + Calculate the sum of all the elements of a list or tuple. This function carries a higher floating point precison level than the standard sum() function by tracking multiple intermediate partial sums. math **@gcd** (a:%integer, b:%integer) Returns the greatest common denominator that both integers share. @@ -1244,9 +1285,30 @@ math **@isclose** (a:%real, b:%real) | (a:%real, b:%real, t:%real) Default tolerance is 1e-09. An alternative tolerance can be specified with the t argument. +math **@lcm** (a:%integer,b:%integer) + Returns the least common multiple of the integers a and b. + math **@mod** (v,d) Implements the modulus operation. Returns the remainder of the quotient v/d. +math **@perm** (n:%integer, k:%integer) + Returns the numbers of ways to choose k items from n total items without repetition and with order. This is equal to n! / (n - k)!. + +math **@prod** x:%list | x:%tuple + Calculate and return the product of all the elements of a list or tuple x. + +math **@remainder** (x,y) + Returns the IEEE 754-style remainder of x with respect to y. + +math **@round** x:%real + Returns x rounded to the nearest integer. If two integers are equally + close, x is rounded to the nearest even integer. + +math **@sum** x:%list | x:%tuple + Calculate and return the sum of all the elements of a list or tuple x. + +math **@trunc** x:%real + Returns x with its fractional component set to 0. Trigonometric functions %%%%%%%%%%%%%%%%%%%%%%% @@ -1260,9 +1322,15 @@ math **@asin** x math **@atan** x Returns the arc tangent of x in radians. The result is between -pi/2 and pi/2. +math **@atan2** (x,y) + Returns the arc tangent of y / x in radians. The result is between -pi and pi. + math **@cos** x Returns the cosine of x radians. +math **@hypot** (x,y) + Returns the Euclidean norm as a real of x and y. This is equivalent to sqrt(x^2 + y^2). + math **@sin** x Returns the sine of x radians. @@ -1299,6 +1367,20 @@ math **@degrees** x math **@radians** x Converts angle x from degrees to radians. +Special functions +%%%%%%%%%%%%%%%%% + +math **@erf** x + Returns the error function (also called the Gauss error function) at x. + +math **@erfc** x + Returns the complement of the error function at x. The is defined as 1 - erf(x) + +math **@gamma** x + Returns the Gamma function at x. + +math **@lgamma** x + Returns the natural logarithm of the absolute value of the Gamma function at x. os ^^ @@ -1351,8 +1433,8 @@ os **@exit** () | v:%integer | msg:%string Signaling an intention to exit the interpreter. When an argument value other than none is provided it is considered a status value. If it is - an integer, zero is considered “successful termination” and any - nonzero value is considered “abnormal termination” by shells and + an integer, zero is considered "successful termination" and any + nonzero value is considered "abnormal termination" by shells and the like. Most systems require it to be in the range 0–127, and produce undefined results otherwise. Some systems have a convention for assigning specific meanings to specific exit codes, @@ -1443,6 +1525,105 @@ os **@syscmd** cmd:%string +patterns +^^^^^^^^ + +The patterns module implements common patterns. +An example: +:: + load system patterns. + + let evens = []. + for num in 1 to 10 do + if num is *patterns@even do + let evens = evens@append(num). + end + end + assert(evens is [2,4,6,8,10]). +Common number sets +%%%%%%%%%%%%%%%%%% + +patterns **@digit** \: %integer + Matches single digit integers. + +patterns **@even** \: %integer + Matches integers which are even numbers. + +patterns **@nat** \: %integer + Matches integers which are natural numbers. + +patterns **@negative** \: %integer | %real + Matches negative reals and integers. + +patterns **@neg_int** \: %integer + Matches negative integers. + +patterns **@neg_int** \: %integer + Matches negative integers. + +patterns **@odd** \: %integer + Matches integers which are odd numbers. + +patterns **@positive** \: %integer | %real + Matches positive reals and integers. + +patterns **@pos_int** \: %integer + Matches positive integers. + +patterns **@pos_real** \: %real + Matches postive reals. + +patterns **@prime** \: %integer + Matches prime numbers. + +patterns **@zero** \: %integer | %real + Matches the value 0, either as an integer or a real. + +Containers +%%%%%%%%%% + +patterns **@bool_list** \: %list + Matches lists which only contain booleans. + +patterns **@func_list** \: %list + Matches lists which only contain functions. + +patterns **@int_list** \: %list + Matches lists which only contain integers. + +patterns **@list_list** \: %list + Matches lists which only contain lists. + +patterns **@real_list** \: %list + Matches lists which only contain reals. + +patterns **@str_list** \: %list + Matches lists which only contain strings. + +patterns **@tuple_list** \: %list + Matches lists which only contain tuples. + +Strings +%%%%%%% + +patterns **@alphabetic** \: %string + Matches strings which only contain alphabetic characters. + +patterns **@alphanumeric** \: %string + Matches strings which only contain alphanumeric characters. + +patterns **@lowercase** \: %string + Matches strings which only contain lowercase alphabetic characters. + +patterns **@numeric** \: %string + Matches strings which only contain numeric characters. + +patterns **@uppercase** \: %string + Matches strings which only contain uppercase alphabetic characters. + + + + pick ^^^^ diff --git a/docs/Reference Guide.txt b/docs/Reference Guide.txt index 7dfefe74..225d5fb7 100644 --- a/docs/Reference Guide.txt +++ b/docs/Reference Guide.txt @@ -673,7 +673,7 @@ where ``*`` means zero or more occurrences of the syntactic unit ``?`` means that the syntactic unit is optional. Simple terminals are written in quotes. :: -#include "/tmp/grammar.tmp" +#include "../asteroid/grammar.txt" Notes on Function Argument Notation ----------------------------------- @@ -1059,6 +1059,8 @@ math **@pi** math **@e** The mathematical constant e = 2.718281…, to available precision. +math **@tau** + The mathematical constant τ = 6.283185…, to available precision. Power and logarithmic functions %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% @@ -1066,34 +1068,65 @@ Power and logarithmic functions math **@exp** x:%integer Returns e raised to the power x, where e = 2.718281… is the base of the natural logarithm. +math **@expm1** x + Returns e raised to the power x minus 1. This function maintains a higher level of precision then the standard operation. + +math **@isqrt** x:%real + Returns the floor of the square root of x as a integer. + +math **@ldexp** (x,i) + Returns x * (2^i). + math **@log** x | (x, base:%integer) If only argument x is the input, return the natural logarithm of x (to base e). If two arguments, (x, base:%integer), are given as input, return the logarithm of x to the given base, calculated as log(x)/log(base). +math **@log1p** x + Returns the natural logarithm of 1 + x. + +math **@log2** x + Returns the base 2 logarithm of x. + +math **@log10** x + Returns the base 10 logarithm of x. + math **@pow** (b, p:%integer) - Return b raised to the power p. The return type depends on the type + Returns b raised to the power p. The return type depends on the type of the base. math **@sqrt** x - Return the square root of x as a real. - + Returns the square root of x as a real. Number-theoretic and representation functions %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% math **@abs** x - Return that absolute value of x. The return type depends on the type of x. + Returns that absolute value of x. The return type depends on the type of x. math **@ceil** x:%real Returns the ceiling of x: the smallest integer greater than or equal to x. +math **@comb** (n:%integer,k:%integer) + Returns the numbers of ways to choose k items from n total items without repetition and without order. This is equal to n! / k!(n - k)!. + +math **@copysign** (x,y) + Returns a real with the absolute value of x and the sign of y. + +math **@dist** (x,y) + Return the Euclidean distance as a float between two points x and y, each given as a tuple or list of coordinates. + +math **@factorial** (n:%integer) + Returns the factorial of the integer n. + math **@floor** x:%real Returns the floor of x: the largest integer less than or equal to x. -math **@round** x:%real - Returns x rounded to the nearest integer. If two integers are equally - close, x is rounded to the nearest even integer. +math **@fmod** (v,d) + Implements the modulus operation as defined by the platform C library. This is equal to v - n*d for some integer n such that the result has the same sign as v and magnitude less than abs(d). + +math **@fsum** x:%list | x:%tuple + Calculate the sum of all the elements of a list or tuple. This function carries a higher floating point precison level than the standard sum() function by tracking multiple intermediate partial sums. math **@gcd** (a:%integer, b:%integer) Returns the greatest common denominator that both integers share. @@ -1103,9 +1136,30 @@ math **@isclose** (a:%real, b:%real) | (a:%real, b:%real, t:%real) Default tolerance is 1e-09. An alternative tolerance can be specified with the t argument. +math **@lcm** (a:%integer,b:%integer) + Returns the least common multiple of the integers a and b. + math **@mod** (v,d) Implements the modulus operation. Returns the remainder of the quotient v/d. +math **@perm** (n:%integer, k:%integer) + Returns the numbers of ways to choose k items from n total items without repetition and with order. This is equal to n! / (n - k)!. + +math **@prod** x:%list | x:%tuple + Calculate and return the product of all the elements of a list or tuple x. + +math **@remainder** (x,y) + Returns the IEEE 754-style remainder of x with respect to y. + +math **@round** x:%real + Returns x rounded to the nearest integer. If two integers are equally + close, x is rounded to the nearest even integer. + +math **@sum** x:%list | x:%tuple + Calculate and return the sum of all the elements of a list or tuple x. + +math **@trunc** x:%real + Returns x with its fractional component set to 0. Trigonometric functions %%%%%%%%%%%%%%%%%%%%%%% @@ -1119,9 +1173,15 @@ math **@asin** x math **@atan** x Returns the arc tangent of x in radians. The result is between -pi/2 and pi/2. +math **@atan2** (x,y) + Returns the arc tangent of y / x in radians. The result is between -pi and pi. + math **@cos** x Returns the cosine of x radians. +math **@hypot** (x,y) + Returns the Euclidean norm as a real of x and y. This is equivalent to sqrt(x^2 + y^2). + math **@sin** x Returns the sine of x radians. @@ -1158,6 +1218,20 @@ math **@degrees** x math **@radians** x Converts angle x from degrees to radians. +Special functions +%%%%%%%%%%%%%%%%% + +math **@erf** x + Returns the error function (also called the Gauss error function) at x. + +math **@erfc** x + Returns the complement of the error function at x. The is defined as 1 - erf(x) + +math **@gamma** x + Returns the Gamma function at x. + +math **@lgamma** x + Returns the natural logarithm of the absolute value of the Gamma function at x. os ^^ @@ -1210,8 +1284,8 @@ os **@exit** () | v:%integer | msg:%string Signaling an intention to exit the interpreter. When an argument value other than none is provided it is considered a status value. If it is - an integer, zero is considered “successful termination” and any - nonzero value is considered “abnormal termination” by shells and + an integer, zero is considered "successful termination" and any + nonzero value is considered "abnormal termination" by shells and the like. Most systems require it to be in the range 0–127, and produce undefined results otherwise. Some systems have a convention for assigning specific meanings to specific exit codes, @@ -1302,6 +1376,98 @@ os **@syscmd** cmd:%string +patterns +^^^^^^^^ + +The patterns module implements common patterns. +An example: +:: +#include "../asteroid/test-suites/ref-programs/patterns.ast" + +Common number sets +%%%%%%%%%%%%%%%%%% + +patterns **@digit** \: %integer + Matches single digit integers. + +patterns **@even** \: %integer + Matches integers which are even numbers. + +patterns **@nat** \: %integer + Matches integers which are natural numbers. + +patterns **@negative** \: %integer | %real + Matches negative reals and integers. + +patterns **@neg_int** \: %integer + Matches negative integers. + +patterns **@neg_int** \: %integer + Matches negative integers. + +patterns **@odd** \: %integer + Matches integers which are odd numbers. + +patterns **@positive** \: %integer | %real + Matches positive reals and integers. + +patterns **@pos_int** \: %integer + Matches positive integers. + +patterns **@pos_real** \: %real + Matches postive reals. + +patterns **@prime** \: %integer + Matches prime numbers. + +patterns **@zero** \: %integer | %real + Matches the value 0, either as an integer or a real. + +Containers +%%%%%%%%%% + +patterns **@bool_list** \: %list + Matches lists which only contain booleans. + +patterns **@func_list** \: %list + Matches lists which only contain functions. + +patterns **@int_list** \: %list + Matches lists which only contain integers. + +patterns **@list_list** \: %list + Matches lists which only contain lists. + +patterns **@real_list** \: %list + Matches lists which only contain reals. + +patterns **@str_list** \: %list + Matches lists which only contain strings. + +patterns **@tuple_list** \: %list + Matches lists which only contain tuples. + +Strings +%%%%%%% + +patterns **@alphabetic** \: %string + Matches strings which only contain alphabetic characters. + +patterns **@alphanumeric** \: %string + Matches strings which only contain alphanumeric characters. + +patterns **@lowercase** \: %string + Matches strings which only contain lowercase alphabetic characters. + +patterns **@numeric** \: %string + Matches strings which only contain numeric characters. + +patterns **@uppercase** \: %string + Matches strings which only contain uppercase alphabetic characters. + + + + pick ^^^^ diff --git a/docs/generate_docs b/docs/generate_docs deleted file mode 100755 index 4352b283..00000000 --- a/docs/generate_docs +++ /dev/null @@ -1,24 +0,0 @@ -#!/bin/bash - -echo "generating User Guide.rst" -#cpp -w -P -traditional "User Guide.txt" > "User Guide.rst" -pcpp --passthru-comments --line-directive nothing "User Guide.txt" > "User Guide.rst" - -echo "generating Reference Guide.rst" -# note: we need to strip multiline C comments manually -# because cpp likes to preserve newlines of multiline comments... -bash strip ../asteroid/grammar.txt >/tmp/grammar.tmp -#cpp -w -P -traditional "Reference Guide.txt" > "Reference Guide.rst" -pcpp --passthru-comments --line-directive nothing "Reference Guide.txt" > "Reference Guide.rst" - -echo "generating Asteroid in Action.rst" -#cpp -w -P -traditional "Asteroid in Action.txt" > "Asteroid in Action.rst" -pcpp --passthru-comments --line-directive nothing "Asteroid in Action.txt" > "Asteroid in Action.rst" - -echo "generating Quickstart Tutorial.rst" -#cpp -w -P -traditional "Quickstart Tutorial.txt" > "Quickstart Tutorial.rst" -pcpp --passthru-comments --line-directive nothing "Quickstart Tutorial.txt" > "Quickstart Tutorial.rst" - -echo "generating MAD.rst" -#cpp -w -P -traditional "MAD.txt" > "MAD.rst" -pcpp --passthru-comments --line-directive nothing "MAD.txt" > "MAD.rst" diff --git a/docs/generate_docs.py b/docs/generate_docs.py new file mode 100755 index 00000000..e80d12d7 --- /dev/null +++ b/docs/generate_docs.py @@ -0,0 +1,29 @@ +''' +This python script generates the RST files for our documentation. + +NOTE: make sure that you have PCPP installed on your system before attempting +to generate documentation, + + pip install pcpp +''' + +import subprocess + +try: + print("generating User Guide.rst") + subprocess.run(["pcpp","--passthru-comments","--line-directive","nothing","-o","User Guide.rst","User Guide.txt"]) + + print("generating Reference Guide.rst") + subprocess.run(["pcpp","--passthru-comments","--line-directive","nothing","-o","Reference Guide.rst","Reference Guide.txt"]) + + print("generating Asteroid in Action.rst") + subprocess.run(["pcpp","--passthru-comments","--line-directive","nothing","-o","Asteroid in Action.rst","Asteroid in Action.txt"]) + + print("generating Quickstart Tutorial.rst") + subprocess.run(["pcpp","--passthru-comments","--line-directive","nothing","-o","Quickstart Tutorial.rst","Quickstart Tutorial.txt"]) + + print("generating MAD.rst") + subprocess.run(["pcpp","--passthru-comments","--line-directive","nothing","-o","MAD.rst","MAD.txt"]) +except FileNotFoundError as e: + print(str(e)) + exit(1) diff --git a/docs/strip b/docs/strip deleted file mode 100644 index c8525d8e..00000000 --- a/docs/strip +++ /dev/null @@ -1,57 +0,0 @@ -#!/bin/bash -# Strip C comments -# by Stewart Ravenhall -- 4 October 2000 -# Un-Korn-ized by Paolo Bonzini -- 24 November 2000 -# adapted to bash by Lutz Hamel -- 6 February 2022 - -# Strip everything between /* and */ inclusive - -# Copes with multi-line comments, -# disassociated end comment symbols, -# disassociated start comment symbols, -# multiple comments per line - -# Check given file exists -program=`echo $0|sed -e 's:.*/::'` -if [ "$#" = 1 ] && [ "$1" != "-" ] && [ ! -f "$1" ]; then - echo "$program: $1 does not exist" - exit 2 -fi - -# Create shell variables for ASCII 1 (control-a) -# and ASCII 2 (control-b) -a="`echo | tr '\012' '\001'`" -b="`echo | tr '\012' '\002'`" - -sed ' - # If no start comment then go to end of script - /\/\*/!b - :a - s:/\*:'"$a"':g - s:\*/:'"$b"':g - - # If no end comment - /'"$b"'/!{ - :b - - # If not last line then read in next one - $!{ - N - ba - } - - # If last line then remove from start - # comment to end of line - # then go to end of script - s:'"$a[^$b]"'*$:: - bc - } - - # Remove comments - '"s:$a[^$b]*$b"'::g - /'"$a"'/ bb - - :c - s:'"$a"':/*:g - s:'"$b"':*/:g -' $1