SCiPL

From Esolang
Jump to navigation Jump to search

SCiPL (SCi Programming Language)

The SCi programming language is a high-level, interpreted, dynamically typed programming language created by User:Alx.

SCiPL - Data Types

NULL Initialized at runtime under names (nil, NULL). This is the NULL object.
bool Represented in code as 'true' or 'false'.
string Represented in code as single or double-quoted literals.
int Represented in code as either a hexadecimal literal, or base-10.
map Spawned via the 'map' function. Allows for key-value tables, aka the map.
table Represented in code with opening curly braces and closing curly braces.
function Type for function protos.
float 32-bit floating-point numbers.
extern External types, like char-arrays.

SCiPL - Syntax

The SCiPL syntax follows the Lua (5.1) syntax, however functions very differently from Lua.

Differences

1. SCiPL has only one scope, being the global scope. Local assignments have no effect on the scope.

2. locally assigning in SCiPL, assigns x-amount of immediate variables to a singular value, whereas normal assignment usually requires the same amount of values to pair the variables. It is also worth noting that if there is no value given for the local assignment, they will all be assigned to the value in the metavariable called '__setslot', which is initialized as NULL. i.e;

local a, b, c    -- a, b, and c are all assigned to the contents of the metavariable __setslot
local a, b, c = 1 -- a, b and c are all assigned to 1.
a, b, c = 1       -- invalid - there must be more values to match the sequence.

3. Function proto parameter names are set as global variables, once called. i.e;

function a_function(a, b)
 return a + b
end

a_function(1, 2)

'a' and 'b' are both now global variables, assigned to 1 and 2.

4. Non-builtin function calls (if a value is returned explicitly in the function body) will return the values inside a table. However, if there is no return statement, the function will not return a table, but instead return NULL. If a function body has a return statement, there must be a value to return. i.e;

function ex() -- valid syntax
 result = 1 + 1
 return result
end

function ex() -- invalid syntax
 result = 1 + 1
 return
end

5. If statements cannot have elseif-else clauses. i.e;

if conditions then
 print(NULL, 1)
end

is the only accepted form of if statement.

6. Table indexes start at 0, not 1. Tables also do not support key-value pairing. i.e;

a_table = { -- valid table
 1,
 2,
 3,
 4
}

a_table = { -- invalid table
 ["key"] = 1,
 ["key2"] = 2,
}

7. Key-value paired tables (aka the map type) can be spawned using builtin 'map' function, which takes tables paired with key-values as key and value pairs. i.e;

my_map = map(
 {"key1",  555},
 {2, "value"}
)

8. Function call argument unpacking is very different. In order to call a function with variable-sized arguments, you cannot use the 'unpack' function, you must comment --[[UNPACK]] before the function call, and the last argument will be unpacked for the function call, which is assumed to be a table. i.e;

--[[UNPACK]]vararg_call(1, {2, 3, 4})

9. f-strings are supported. f-strings are almost pythonic, but are quite different to python's f-strings, as they are just function calls. You can make one look pythonic by a non-parenthesized function call, i.e;

formatted_string = f{"{} + {} is {}", 1, 1, 2}
print(NULL, formatted_string)

10. There is no 'break' keyword to break out of loops.

More... There are also many more differences from Lua to SCiPL, such as builtin libraries, builtin functions, and said data types. A list of builtin functions, and their descriptions are below.

Name Type Description Parameter Type(s)
__include Builtin Includes a SCi module file (compiled .(csci), or plain (.sci)) into the current namespace. string;
__discard Special Builtin Discard the topmost item on the stack.
__delref Special Builtin Deletes a reference or variable by name. string;
__getenv Special Builtin Returns the current namespace.
__base Builtin Returns a list of all builtins.
__incrref Special Builtin Increments a variable if variable is an int by 1. Used for optimization. string;
__decrref Special Builtin Decrements a variable if variable is an int by 1. Used for optimization. string;
map Builtin The function that allows spawning key-value tables, aka the map type. *table;
print Builtin Prints an object. First argument is an end specifier, if NULL, the end is a newline. ...; *...
type Builtin Returns the type of the argument as it's name, as a string. ...
math Library A map library of mathematical functions.
string Library A map library for string operations.
table Library A map library for table operations.
iter Builtin Spawns an iterator, usually used for 'for' iterations in an iterable. (table, map);
input Builtin Captures stdin with a prompt as the first argument. No prompt if empty. string; bool;
stoi Builtin Typecasts a string into an int. string;
tostring Builtin Typecasts an object into its string representation. ...;
bit32 Library A map library for bitwise operations. (32-bit)
range Builtin A numerical-range iterator, usually used in for-loops. int; int; int;
f Builtin Returns a formatted string. table;
b Builtin Encodes a string into a byte-string, or char array. string;
unpack Special Builtin Unpacks table items onto the stack. table;
io Library A map library for file operations.
dump Builtin Compiles and returns the bytecode of provided code in string representation. string;
fpairs Builtin Calls a function on every value inside the provided table, and returns an equivalent table with the new items. function; table;
return_call Builtin Calls a function with a table of arguments, and returns the first item in the return table. function; table;

SCiPL - Internals

The current SCiPL interpreter is a stack-based virtual machine. There are currently (as of SCiPL version v0-m6 b) 40 opcodes. The instruction notation is explained below:

The instructions are a fixed size of 40 bits / 5 bytes.

Instruction Type A

First Bit (0)
Operand A: 32 bits
   Opcode: 6 bits
   Opmode: 2 bits
Last Bit (40)

Instruction Type B

First Bit (0)
Operand A: 8 bits
Operand B: 8 bits
Operand C: 16 bits
   Opcode: 6 bits
   Opmode: 2 bits
Last Bit (40)

The current instruction set is described in the following table.

Opcode Description
LOAD_GBL Loads a global variable onto the stack.
LOAD_KST Loads a constant from the constants pool onto the stack.
LOAD_UL Loads an unsigned-long integer onto the stack.
IJMP Incremental absolute jump.
DJMP Decremental absolute jump.
MKTBL Creates a table consuming x-amount of items from the stack.
MKMAP Creates a key-value pair map consuming x-amount of items from the stack. Obsolete opcode.
SUBSCR Performs subscription on a table.
SET_GBL Pops an item off the stack, and sets it under a global variable.
SET_SUBSCR Subscripts a table or map, and assigns the key/index as a value.
ADD Pops two items off the stack, and performs addition.
MUL Pops two items off the stack, and performs multiplication.
DIV Pops two items off the stack, and performs division.
POW Pops two items off the stack, and performs exponentiation.
MOD Pops two items off the stack, and performs modulo.
SUB Pops two items off the stack, and performs subtraction.
DISCARD Pops the topmost stack item off the stack.
CALL Consumes x-amount of items off the stack as arguments, +1 extra as the callable, and calls.
NADD Equivalent to ADD, except with variables. Used for optimization.
NMUL Equivalent to MUL, except with variables. Used for optimization.
NDIV Equivalent to DIV, except with variables. Used for optimization.
NPOW Equivalent to POW, except with variables. Used for optimization.
NMOD Equivalent to MOD, except with variables. Used for optimization.
NSUB Equivalent to SUB, except with variables. Used for optimization.
MKFUNC Creates a callable function from TOS, which is assumed to be the function proto.
IJMP_FALSE Conditional incremental jump.
DJMP_FALSE Conditional decremental jump.
NOT Performs a logical NOT on the topmost stack item.
LAND Pops two items off the stack and performs a logical AND.
LOR Pops two items off the stack and performs a logical OR.
RETURN_NUL Returns NULL. This is at the end of every code body.
RETURN Returns x-amount of items from the stack, in a table.
CMP Pops two items off the stack, and performs one of the following actions: <, >, <=, >=, ~=, ==.
LOAD_NUL Loads NULL onto the stack.
LOAD_BOOL Loads a boolean onto the stack, either being true or false.
CONCAT Pops two items off the stack which are typecasted to strings, and concatenates them together.
GET_LEN Gets the length of TOS, which is assumed to be either a string, table map or other iterable.
FORJMP For-iterator conditional jump. Jumps to offset x once iterator is exhausted.
NEG Inverts the topmost stack item.
LD_FLOAT32 Loads a float onto the stack.

SCiPL - Extras

Example Programs

1 - Guess the Number Game

__include("librandom")

min = stoi(input("Pick a number: "))
max = stoi(input("Pick another: "))
n = unpack(randint(min, max))

guesses = 1
print(NULL, f{"I'm thinking of a number between {} and {}. Good luck!", min, max})

while true do
 check = stoi(input("Your guess: "))

 if (check == n) then
  return print(NULL, f{"You guessed my number in {} tries!", guesses})

 end

 if (check < n) then
  print(NULL, "Too low!")

 end

 if (check > n) then
  print(NULL, "Too high!")

 end

 guesses = guesses + 1

end

STDOUT:

Pick a number: 1
Pick another: 10
I'm thinking of a number between 1 and 10. Good luck!
Your guess: 1
Too low!
Your guess: 4
Too low!
Your guess: 7
Too high!
Your guess: 6
You guessed my number in 4 tries!

2 - Calculator App

play = true

function add()
 a = stoi(input("Number A > "))
 b = stoi(input("Number B > "))

 print(NULL, "The result of A + B is:", a + b)
end

function multiply()
 a = stoi(input("Number A > "))
 b = stoi(input("Number B > "))

 print(NULL, "The result of A * B is:", a * b)
end

function sub()
 a = stoi(input("Number A > "))
 b = stoi(input("Number B > "))

 print(NULL, "The result of A - B is:", a - b)
end

function get_input(a)
 print(NULL, [[
[A]dd
[M]ultiply
[S]ub
[Q]uit
]])

 test = input(" > ")
 test = string.upper(string.subscript(test, 0, 1))

 if (test == "A") then
  return add()

 end

 if (test == "M") then
  return multiply()

 end

 if (test == "S") then
  return sub()

 end

 if (test == "Q") then
  play = false

 end
end

print(NULL, "Welcome to the Calculator:")
while play do
 get_input()

end

STDOUT:

Welcome to the Calculator:

[A]dd
[M]ultiply
[S]ub
[Q]uit

 > m
Number A > 10
Number B > 5
The result of A * B is: 50

[A]dd
[M]ultiply
[S]ub
[Q]uit

 > q

3 - XOR cipher message

__include("libcodec")

function xor_cipher(plaintext, key)
 r = ""
 for i=0, #plaintext do
  key_byte = string.byte(key, (i % #key))
  plaintxt_byte = string.byte(plaintext, i)

  r = r .. string.char(bit32.bxor(plaintxt_byte, key_byte))
 end

 return r
end

text, key = "here is a message i need ciphered", "and a key"
ciphertext = unpack(xor_cipher(text, key))
print(NULL, tostring(encode(b(ciphertext), "hex"), 1))

plaintext = unpack(xor_cipher(ciphertext, key))
print(NULL, plaintext)

STDOUT:

090b164541491845184103015312410c0059084e0a4504444b0610110601520444
here is a message i need ciphered

4 - Adler32 Checksum Algorithm

function adler32(stream)
 local ctr, B = 0
 A = 1

 while (ctr < #stream) do
  c = string.byte(stream, ctr)
  A = (A + c) % 0xFFF1
  B = (A + B) % 0xFFF1

  ctr = ctr + 1
 end

 result = bit32.bor(bit32.bshl(B, 16), A)
 return result

end

data = {"a very long string, indeed",
"data1",
"data2",
"data",
"dtaa"
}

for i in iter(data) do
 v = unpack(adler32(i))
 print(NULL, v)
 __discard()

end

STDOUT:

2140998020
97255884
97321421
67109275
68354459

Update

Regarding the `vararg call` in SCiPL Syntax section 8, I mean unpack, not vararg