sms

GitHub Lines of code GitHub top language GitHub language count GitHub all releases GitHub contributors GitHub commit activity img GitHub repo size GitHub Workflow Status

Introduction:

SMS (Symbolic Math System) is a math-focused scripting language for POSIX friendly environments. SMS has built-in functions for arithmetic, trigonometry, algebra, calculus, file access and more. SMS aims to become a simple general purpose programming language. SMS is still in early stages of development. SMS can be downloaded and installed from the Releases page on GitHub. The latest source code may have undocumented changes and this document is synchronized with the project at the point of the latest release: GitHub latest release (latest by date)

Details

In addition to providing a command line, SMS can interpret files. Run sms -h for command line options.

Unlike Javascript, Math functions in SMS are global keywords.

For example, taking a square root in javascript may look like Math.sqrt(x). In SMS, this same function is permanently available as sqrt(x).

Another major difference between SMS and javascript is that SMS provides the meta operator (:) which allows developers to capture expressions for metaprogramming.

For example, taking a derivative of sin(x) with respect to x may be done with diff(:sin(x),:x); where the colon prevents SMS from evaluating the input and ultimately preserving the symbolic expression.

The following is ‘hello world’ in SMS:

putln("Hello world!");

SMS versions have 2 significant figures (like 0.190) during a milestone point. During these versions, development focuses on documentation, unit tests, and bugs.

SMS versions with 3 significant figures (like 0.191) are in feature development, so they may lack documentation for new features, and might have unannounced changes to existing features, are are generally less stable than the milestone versions. This readme is only syncronized with the last milestone version.

Cheat Sheet

Click on the chapter names below to expand the cheat sheet for that chapter. Line comments start with #.

Math 1. a + b ; # Add two numbers 2. a * b ; # Multiply two numbers 3. a - b ; # Subtract two numbers 4. a / b ; # Divide a by b 5. a ^ b; # Raise a to the power of b 6. sin(x); cos(x); tan(x); # Trig functions 7. sinh(x); cosh(x); tanh(x); # Hyperbolic trig functions 8. sec(x); csc(x); cot(x); # Inverse trig funtions 9. sech(x); csch(x); coth(x); # Inverse hyperbolic trig functions 10. abs(x); # Return the absolute value of x 11. exp(x); # Euler's number, raised to the power of x 12. ln(x); # Natural log of x 13. log(b,x); # Log, base b of x 14. sqrt(x); # Square root of x 15. random(); # Generate a random number from 0 to 1 16. seed(number); # Seed the random generator based on an integer 17. round(); # Nearest integer 18. diff(:sin(x),:x); # Return the derivative of sin(x) with respect to x 19. simp(:expr); # Attempt to simplify the given expression
Equality 1. a == b # returns true if a is the same value as b, else, returns false 2. a > b # returns true if a is more than b, else, returns false 3. a < b # returns true if a is less than b, else ,returns false 4. a >= b # returns true if a is more than or equal to b, else ,returns false 5. a <= b # returns true if a is less than or equal to b, else ,returns false 6. true is true # the is keyword returns true if both objects are the same instance
Flow Control 1. return x ; # return this value from a function 2. twice = (x) => 2 * x; # make a function that doubles numbers 3. quad = (x,a,b,c) => a*x^2+b*x+c; # a quadratic function in x 4. { command1 ; command2 ; ... }; # A block of commands acts as 1 command 5. if(condition) command; # execute command if true, else return false 6. if(condition) command1 else command2; # if condition evaluates to true, executes command1, else executes command2 7. while(condition) statement # continually repeat statement until condition is false 8. for(let a = 0;a < 100;a = a + 1) putln(toStr(a)) # will print 0 to 100 8. doWhile ( condition ) statement # Repeating statement until condition is false (checking condition after running statement) 9. map( function, expression ) # return a new array where each element is the result of applying function to the correlating element of the given expression 10. not( boolean ) # if boolean is false, returns true, otherwise, returns false 11. EXPR or EXPR # returns true of either expression is true, else false 12. EXPR and EXPR # returns true of both expressions are true, else false 13. exit(n); # quit SMS and return this integer to the OS as the command return value 14. :sin(x); # capture any expression with the unary meta operator. Use parens to capture more.
Contexts 1. let var = value ; # creates a new variable in the current context with the given value. 2. rm var; # removes the variable from the current context. 3. var = value; # searches for var in this context, then up the parent path, and if found, sets to value, else a new variable is created in the current context. 4. let context = { var1 -> value1; var2 -> value2 }; # builds a context with 2 variables and saves it under the variable 'context' 5. context.var1; # Retreive the value of a specific variable from the context 6. context.var1 = value; # Set the value of a specific variable from the context 7. parent(context); # Return the parent scope of the provided context 8. cxLet(cx,:x,value); # A way to create a new variable in a context or just set it to a new value 9. cxSet(cx,:x,value); # A way to set cx.x=value for a context cx or return false 10. cxGet(cx,:x); # Get a value associated with the given key, or return false 11. cxGetFar(cx,:x,value); # Get the value, searching to higher scopes in the search 12. cxSize(cx); # Return the number of entries in this context 13. cxValues(cx); # Return an array with the values of the context 14. cxKeys(cx); # Return an array with the keys of the context 15. cxDot(cx,:symbol); # Return this variable from this context 16. cxContaining(cx,:key); # Returns the context which contains :key, by looking at cx and its ancetry 17. cxRm(cx, :var); # Remove this entry from the context 18. cxImport(cx1, cx2); # import the key/value pairs from cx1 into cx2. Overwrites existing key values 19. cxSetParent(cx1, cx2); # Set the parent of cx1 to cx2.
Arrays 1. [ expr1, expr2 ] # Create an array by evaluating expressions 2. :[ expr1 , expr2 ] # Create an array of unevaluated expressions 3. array[ i ] # Return the i'th element of the array, where i=0 is the first element 4. array[ i ] = value # Set the ith value of the array. Returns true upon success only 5. size( array ) # Return the number of elements in the array 6. size( expr ) # Return the number of arguments in the expression
Strings 1. let s = "example\nstring"; # s is now a string with a newline escape code (\n) 2. strFind(s,to_find); # Return the first location of to_find 3. strSize(s); # Return the length of string s 4. strEscape(s); # Convert any escape codes into their correlating character 5. "this" str+ "that"; # Return a string that is the concatenation of s1 with s2 in order 6. strPart(s1,start,len) # Return a part of the string, starting at index start, and with length len 7. toStr(object0); # Return the string representation of object0 8. input(); # Allow the user to enter a string of text, which becomes the return value 9. put(s1); # Print the string s1 10. putln(s1); # Print the string s1 and go to the next line 11. strSplit(haystack,needle); # Return an array of strings which are the parts of haystack, split up by instances of needle
Files 1. fileRead("test.txt"); #reads test.txt , paths are relative to the working directory 2. fileWrite(fname, content); # takes a string for the file name to write to, and a string for the content to write 3. fileParse(fname); # Parses the file into a single object 4. cd("..") ; # change working directory 5. pwd(); # returns the working directory 6. ls() ; # show files and directories at the current working directory
Date and Time 1. date() # returns the date and time in the form of an array of 9 numbers, listed with their array index: # date()[0]: seconds (0-60) # date()[1]: minutes (0-59) # date()[2]: hours (0-23) # date()[3]: Day of month (1-31) # date()[4]: months since January (0-11) # date()[5]: Years since 1900 # date()[6]: Days since Sunday (0-6) # date()[7]: Days since January 1 (0-365) # date()[8]: Dayslights Savings flag (positive if daylight savings is in effect, 0 if not, negative if this is unknown) 2. time() # returns an array with 2 values: the number of seconds since January 1, 1970, then the number of microseconds since the last whole second. 3. dateStr() # returns the date in a 24 character string, like: "Thu Apr 6 01:20:24 2023" 4. sleep(n) # pause process execution for n milliseconds.
Processes 1. osFork(); # returns a process number. If the number is 0, we are in the child process. if the number is more than 0, we are in the same process as before, and the id is the id of the child process. If the number is -1, then forking failed. Check sms_src/fork.sms for an example. 2. osWait(); # If a child process is running, this waits until the process terminates, then returns an array with 2 elements: a process id, and the return code. If there is no child process to wait for, this function returns [-1,1]. Use this function from the parent of a child process made by osFork(). Check sms_src/fork.sms for an example. 3. osExec("path/to/binary"); # Execute another file, and wait until the file returns. The return value of osExec is the return value of the process. 4. exit(n) ; # exit SMS with return code specified by n
Expressions 1. xpOp(:(a+b)); # Returns the id of the operation in the expression 2. xpSetOp(:(a+b),17) # Set the operator 3. xpOpStr(17) # Get the string for an operator
Functions 1. let myFunc = (x,y)=>sqrt(x^2+y^2); # Make a function that depends on x and y 2. let f = fnSetParent(myFunc,parent(self)); # An example of changing the parent context of a function. Check fnSetParent.sms 3. fnXp((x)=>x^2); # Would return x^2 as an expression. same as :(x^2) 4. fnSetXp(funcion, :(expression)); # Mutate the function to have new content 5. fnParams(func); # returns the input params as an array of symbols 6. fnSetParams(func,(:x,:y,:z)); # change the parameter names for a function 7. fnParent(func); # returns the parent context of the function 8. fnSetParent(func, cx); # returns a new function with new parent

How to Download and Run/Install a Release

How to Compile for Latest Features

Required Packages:

The makefile uses clang by default. Edit the first lines of the makefile to use your preferred compiler and make program if necessary.

Once you have the necessary packages installed (GCC/Clang, Flex, and Bison), Change directory to the top level of the project (where LICENSE.txt is located) and run:

make

Upon success, you will have a portable executable called ‘sms’ in the bin directory.

On Linux/Unix systems, You may be able to build and install in one step:

sudo make install

This command builds the executable and copies it to /usr/local/bin/sms

Language Features, Specs and Design:

Plans:

Great Ways to Contribute: