KevinScript (abbreviated "KS") is a programming language inspired by Python and Javascript.
KS requires Python to run.
Download this repository to a directory of your choosing. For example, C:\programming\Github projects\KevinScript
.
You can experiment with KS right away by using the REPL. Execute python -m ks
with no arguments.
C:\programming\Github projects\KevinScript>python -m ks
>>> print("Hello, world!")
...
Hello, world!
Exit the REPL with ctrl-C or ctrl-Z.
You can execute KS source files by supplying a file name to python -m ks
.
C:\programming\Github projects\KevinScript>python -m ks samples\prime_detector.k
Prime numbers below 100:
2
3
5
7
11
13
17
19
23
29
31
37
41
43
47
53
59
61
67
71
73
79
83
89
97
Optionally, you may install KevinScript as a package. This will make it accessible from any directory. From the KevinScript directory, execute:
python setup.py install
Now you can access KevinScript by using KevinScript
instead of python -m ks
.
There are only two Boolean values. They are named True
and False
.
>>> True;
True
>>> False;
False
>>> True and False;
False
>>> True or False;
True
An Integer is represented by a sequence of digits. Like in most other languages, they can be manipulated using typical arithmetic operators.
>>> 12345;
12345
>>> 2+2;
4
>>> 23-42;
-19
>>> 6*7;
42
>>> 100/4;
25
>>> 16/3;
5
>>> 15 % 2;
1
Note that if division would result in a non-integer, the operator rounds downwards.
>>> 3/2;
1
>>> -3/2;
-2
The List is the primary compound data type. It can be used to collect objects together.
>>> seq = [4, 8, 15, 16, 23, 42];
>>> seq[0];
4
>>> seq[5];
42
>>> seq.size();
6
>>> seq.append(100);
>>> seq[0] = 999;
>>> seq;
[999, 8, 15, 16, 23, 42, 100]
>>> seq.size();
7
>>> for(item in seq){print(item);}
999
8
15
16
23
42
100
A list can contain any type of object. Elements do not need to share the same type.
Strings are collections of characters.
>>> print("Hello, World!");
Hello, World!
None
is an object used to indicate the absence of a value. it is the return value of any function that does not explicitly return anything.
>>> function f(){
... "this function does nothing";
... }
>>> print(f());
None
All types in KevinScript inherit basic behavior from Object
. This is true for both built-in types, and user defined types.
The Type object is the type of all types. It can be used to create new types, although it is usually preferable to use the class declaration statement instead.
>>> Object.type;
<type 'Type'>
>>> Integer.type;
<type 'Type'>
>>> String.type;
<type 'Type'>
Parameters needed to call type:
- name: a string describing the type.
- parent: the type that this type should inherit from. Use
Object
if you don't want anything in particular. - methods: a list of even length. Each even-indexed item is the string name of a method, and each odd-indexed item is the callable describing that method's behavior.
For example,
>>> Fred = Type("Fred", Object, ["durf", function(self) {return 23;}]);
>>> x = Fred();
>>> x.durf();
23
The type of all functions. Can't be called by the user. Only used for type checking.
(coming soon?)
Used to bind values to variables.
>>> x = 23;
>>> y = x;
>>> x = 42;
>>> x;
42
>>> y;
23
Assignment is by reference. If two variables refer to the same value, then calling a mutating method on one will mutate the other.
>>> a = [1,2,3];
>>> a.size();
3
>>> b = a;
>>> b.append(42);
>>> b.size();
4
>>> a.size();
4
Here, a
and b
refer to the same list, so a.size()
changes from 3 to 4 when we append to b
.
Causes a block of code to only execute if the condition is True.
>>> if (1 < 100){
... print("the if condition passed");
... }
the if condition passed
>>> if (999 < 100){
... print("the if condition passed");
... }
>>>
Following the if block, you may have an else
block. The contents of this block only executes if the condition is not True.
>>> if (999 < 100){
... print("the if condition passed");
... } else {
... print("the if condition failed");
... }
the if condition failed
Causes a block of code to repeat as long as the predicate is True.
>>> x = 1;
>>> while (x < 100){
... print(x);
... x = x * 2;
... }
1
2
4
8
16
32
64
Repeats a block of code once for each element of the supplied list.
>>> items = [4, 8, 15, 16, 23, 42];
>>> for(x in items){
... print(x);
... }
4
8
15
16
23
42
Creates a Function object, which can later be called in order to execute the code block.
>>> function sum(x,y,z){
... return x+y+z;
... }
>>>
>>> print(sum(16, 23, 42));
81
Creates a new type, which can be called to make new objects of that type.
>>> class Dog{
... function __init__(self, breed){
... self.breed = breed;
... }
... function bark(self){
... print("woof");
... }
... function speak(self){
... print("Hello, I am a dog. My breed is:");
... print(self.breed);
... }
... }
>>> fido = Dog("terrier");
>>> fido.bark();
woof
>>> fido.speak();
Hello, I am a dog. My breed is:
terrier
You can specify a parent class, which your type will inherit methods from.
>>> class Fred{
... function speak(self){
... print("Yabba dabba doo!");
... }
... }
>>> class Barney(Fred){
... }
>>> b = Barney();
>>> b.speak();
Yabba dabba doo!
Terminates a function and presents a value to the calling context. Should not be used if you aren't inside a function.
>>> function frob(){
... return 23;
... print("This line will never execute no matter what");
... }
>>>
>>> print(frob() + 42);
65
An expression statement may contain any one expression. When used inside the REPL, the result of the expression will be printed, unless it is None.
>>> 42;
42
>>> 2+2;
4
>>> "Hello, I am an expression containing a string literal";
Hello, I am an expression containing a string literal
>>> None;
>>>
a statement that doesn't do anything. Represented by a lone semicolon.
>>> ;
>>>
See [Integers] for example usage. You can override the behavior of your own types by defining the appropriate double-underscore methods:
- multiplication -
__mul__
- division -
__div__
- modulus -
__mod__
- addition -
__add__
- subtraction -
__sub__
Used to compare the values of two objects.
>>> 100 > 3;
True
>>> 1 > 3;
False
>>> 4 < 100;
True
>>> 4 == 4;
True
Define the behavior of your own types by defining:
- greater than -
__gt__
- less than -
__lt__
- equals -
__eq__
- does not equal -
__ne__
Used to chain together boolean expressions.
>>> 25 > 0 and 25 < 100;
True
>>> 999 < 0 or 999 > 100;
True
Define the behavior of your own types by defining:
- and -
__and__
- or -
__or__
Similar to the function declaration statement, except it can be used anywhere an expression could go - as an argument to a call, inside a list, etc.
>>> function apply_each(value, functions){
... for(func in functions){
... value = func(value);
... }
... return value;
... }
>>>
>>> funcs = [function(x){return x+1;}, function(y){return y*2;}, function(z){return z-100;}];
>>> print(apply_each(23, funcs));
-52
Function expressions are anonymous. There is no identifier between "function" and the parameter list.
Used to create new lists by applying some expression to each element of an existing list.
>>> x = [1,2,3];
>>> y = [a*2 for a in x];
>>> y;
[2, 4, 6]
An expression can be called by adding a pair of parentheses, which may contain zero to infinity arguments. For example, print
is a function that can be called with one argument.
>>> print(23);
23
The attributes and methods of an object can be accessed using the period operator.
>>> x = Object();
>>> x.foo = 23;
>>> x.foo;
23
Some objects, such as List, support indexed item access.
>>> x = [4, 8, 15, 16, 23, 42];
>>> x[1] = 99;
>>> print(x);
[4, 99, 15, 16, 23, 42]
>>> print(x[1]);
99
Define this behavior in your own types by defining:
- item getting -
__getitem__(self, key)
- item setting -
__setitem__(self, key, value)
An atom expression is one of three things:
- a variable name, ex.
foo
,Object
,print
. - a literal value, ex.
23
,[1,2,3]
,"Hello"
. - any expression inside a pair of parentheses, ex.
(1+2-3*4/5)
.
No, this is a real programming language that has real code. You can download it and it really runs.
Currently nothing. For any programming project you can think of, there is probably a language that would execute it faster and more concisely than this one.
Have you considered using [insert grammar-reading / token-lexing / code-generating / compiler-writing library here]?
KevinScript subscribes to a policy of radical compatibility. It ought to be able to run on any machine that has any Python distribution of 2.7 or higher. We don't want the user to have to download anything else. And anyway, implementing it the hard way builds character.
Working on this project primarily serves as a learning experience about the decisions and pitfalls of language design. Why does Python have two kinds of classes? Why does this
in Javascript sometimes point to the Window object, and sometimes to the object the current method is called on? Trying to do these kinds of things your own way can give valuable insight into the thought process of the original devs, and convey a level of understanding greater than just from reading source code or blog posts.
In addition to perpetually improving the original interpreter, a number of possible spin-off projects are in the planning stage.
JKevinScript - A KS interpreter written in Javascript. Will run in the browser.
KSKevinScript - A KS interpreter written in KevinScript.
Compiled KevinScript - compiles KS to C, which can then be compiled into an executable.
Please submit bug reports and feature requests on the Github Issues page. QA and Design eagerly await your feedback!
We are not actively seeking code contributions at this time.
Concept - Kevin
Design - Kevin
Development - Kevin
Quality Assurance - Kevin
Documentation - Kevin
Branding - Kevin
Public Relations - Kevin
Help Desk - Kevin
Catering - Kevin
Technical advisors and emotional support - the fine members of SOPython