Giter Site home page Giter Site logo

ricardoboss / step Goto Github PK

View Code? Open in Web Editor NEW
5.0 3.0 1.0 1.42 MB

The STEP programming language

Home Page: http://step-lang.dev/

License: MIT License

C# 99.78% Shell 0.20% CSS 0.02%
easy-to-use language programming-language simple step learn learn-programming learn-to-code hacktoberfest hacktoberfest2023

step's Introduction

STEP

STEP

Simple Transition to Elevated Programming

Welcome ๐Ÿ‘‹

STEP is a programming language that is designed to be easy to learn and use.

It is inspired by languages like Python, JavaScript, Dart and C#.

Features

  • Easy to learn and use โ€” It has a simple syntax and a small set of features.
  • Statically typed โ€” You need to declare the type of a variable before you can use it.
  • Interpreted โ€” You don't need to compile your code before you can run it.
  • Cross-platform โ€” You can run it on Windows, Linux and macOS.
  • Open source โ€” You can contribute to the language and its ecosystem.
  • Extensible โ€” You can write your own functions and libraries and import them anywhere.

Installation

To use STEP, you need to set up the STEP CLI.

Check out the installation guide for more information.

Documentation

To get started using STEP, head over to the Guide.

STEP has a standard framework of functions you can use in your programs. An overview of all functions can be found in the Functions section of the wiki.

Additionally, STEP has very graceful error handling. All errors are documented in the Errors section of the wiki.

Contributing

If you want to contribute to STEP, check out the Contributing section in the repository.

Check out the good first issue issues to get started.

If you ever need help, feel free to join @ricardoboss' Discord server.

License

This project is licensed under the MIT license. For more information, read LICENSE.md.

step's People

Stargazers

 avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar

Forkers

chucker

step's Issues

Move Wiki source to docs folder

I want pull requests to be able to update the wiki along with the change they introduce and I don't want to make the wiki publicly editable.

A way to do this is by moving the wiki source into the main repository and use a workflow to synchronize changes.
This article describes this idea: https://nimblehq.co/blog/create-github-wiki-pull-request

I think something like this is a good solution until the documentation outgrows the needs satisfied by a single folder :)

Add beginner-friendly examples

People browsing the examples are probably overwhelmed by the complexity of the examples.
This is in part because they are also used as integration tests and may not reflect what a beginner would look for when searching for code to learn from.

I think a good approach would be to add beginner-friendly example programs that solve a single problem or show a certain aspect of the language.

This would go hand-in-hand with adding tutorials (#29).

Enable trimmed publishes

In order to reduce the size of published binaries, we should leverage /p:PublishTrimmed=true.

Enabling this currently causes build errors:

/Users/ricardo/repos/ricardoboss/STEP/StepLang/Framework/Conversion/ExpressionResultJsonConverter.cs(37,33): error IL2026: Using member 'System.Text.Json.JsonSerializer.Deserialize<TValue>(ref Utf8JsonReader, JsonSerializerOptions)' which has 'RequiresUnreferencedCodeAttribute' can break functionality when trimming application code. JSON serialization and deserialization might require types that cannot be statically analyzed. Use the overload that takes a JsonTypeInfo or JsonSerializerContext, or make sure all of the required types are preserved. [/Users/ricardo/repos/ricardoboss/STEP/StepLang/StepLang.csproj]
/Users/ricardo/repos/ricardoboss/STEP/StepLang/Framework/Conversion/ExpressionResultJsonConverter.cs(56,33): error IL2026: Using member 'System.Text.Json.JsonSerializer.Deserialize<TValue>(ref Utf8JsonReader, JsonSerializerOptions)' which has 'RequiresUnreferencedCodeAttribute' can break functionality when trimming application code. JSON serialization and deserialization might require types that cannot be statically analyzed. Use the overload that takes a JsonTypeInfo or JsonSerializerContext, or make sure all of the required types are preserved. [/Users/ricardo/repos/ricardoboss/STEP/StepLang/StepLang.csproj]
/Users/ricardo/repos/ricardoboss/STEP/StepLang/Framework/Conversion/JsonDecodeFunction.cs(17,16): error IL2026: Using member 'System.Text.Json.JsonSerializer.Deserialize<TValue>(String, JsonSerializerOptions)' which has 'RequiresUnreferencedCodeAttribute' can break functionality when trimming application code. JSON serialization and deserialization might require types that cannot be statically analyzed. Use the overload that takes a JsonTypeInfo or JsonSerializerContext, or make sure all of the required types are preserved. [/Users/ricardo/repos/ricardoboss/STEP/StepLang/StepLang.csproj]
/Users/ricardo/repos/ricardoboss/STEP/StepLang/Framework/Conversion/JsonEncodeFunction.cs(17,20): error IL2026: Using member 'System.Text.Json.JsonSerializer.Serialize<TValue>(TValue, JsonSerializerOptions)' which has 'RequiresUnreferencedCodeAttribute' can break functionality when trimming application code. JSON serialization and deserialization might require types that cannot be statically analyzed. Use the overload that takes a JsonTypeInfo or JsonSerializerContext, or make sure all of the required types are preserved. [/Users/ricardo/repos/ricardoboss/STEP/StepLang/StepLang.csproj]

These errors occur, because the jsonDecode and jsonEncode functions need to be able to load any type at runtime, which prevents the binary from being trimmed.

The error messages suggest using specific overloads which can be used to determine which types are needed to decode values at runtime.

Use `GitVersion` to automatically retrieve the assembly version from git

Describe the feature

When releasing new versions, it is easy to forget to increase the assembly version.

To mitigate that, I'd suggest adding GitVersion as an MSBuild task.
That way, the version smoothly integrates with the current release flow:

  1. Add a git tag with the new version (SEMVER)
  2. Push the tag
  3. The GitHub workflow publish gets triggered
  4. The publish.sh script is run
  5. The StepLang.CLI project is built and GitVersion determines the assembly version
  6. A new release on GitHub is drafted

Step 5 is the crucial step here, but does not require modification.

The only modification required would be to install GitVersion and configure it.

Additionally, it would be nice to have access to the current STEP version from the program (like PHPs PHP_VERSION global constant).

Please make sure you did the following before submitting your feature request:

  • I have searched the issues to make sure this is not a duplicate

`format` command

Sharing code with others is key to finding and fixing issues. A common, standardized code style helps quickly getting a grasp of its meaning.

This item proposes the introduction of a step format command, that normalizes the code style of any STEP program.

Future development might include a way to configure the specifics for the code style that is applied.

"batteries included" HTTP server?

My first experience with programming was via HTML, CSS and Javascript. Maybe a way to host a simple web server using STEP and adding functions for handling requests allows more users to explore the world of web development in an accessible way.

Web development also enables newcomers to see results of their work more easily, as the browser takes care of rendering.

Add tutorials and how-tos

Newcomers likely won't go into the code and look at the example .step files in the Examples folder.

A way to give purpose to using STEP might be to add tutorials and step-by-step (pun intended) guides on how to achieve certain goals. This gives programmers a goal to work towards and gamifies developing with STEP a little bit.

Ideas for Tutorials

  • Calculate pi using the Monte Carlo method
  • Caesar chiffre implementation?
  • Expenses calculator
  • Text adventure?

Ideas for simple examples

As #23 proposed, these are examples for beginners looking for simpler code to learn from.

  • Writing to the terminal
  • Handling user input
  • Handling files

Index operator for strings

Strings should be able to be accessed at certain indexes to read a single character of that string at the given index.

string foo = "hello world!"

println(foo[0]) // h
println(foo[6]) // w

`foreach` loop

Working with certain data types can be cumbersome if the intention is to simply iterate over a list of values.

Currently, to iterate over a list of values or a map, you would need to use a while loop:

list a = [1, 2, 3]
number i = 0
while (i < length(a)) {
    println(a[i])
}

Since iterating over a list is a common use case, I propose to add a foreach statement, that automatically loops over a lists/maps values.

The design could look like that:

list a = [1, 2, 3]
foreach (number value in a) {
    println(value)
}

and for maps with key-value-pairs:

map b = {"a": 1, "b": 2}
foreach (string key: number value in b) {
    println(key, " -> ", value)
}

Escaped characters are not tokenized correctly

Using \ in strings escapes the following character and causes it to be interpreted differently.
This works for " and enables users to declare a string like This is a quote: " like this:

string a = "This is a quote: \""

This, however, does not work for other escaped characters:

string b = "This is a new line: \n"

and results in an UnterminatedStringException:

StepLang.Tokenizing.UnterminatedStringException: A string was not properly terminated

Add a custom sidebar to the wiki

Currently, the folders are not represented in the sidebar in the wiki.

To make it more navigateable, we should add a custom sidebar.

More extensive standard framework

The goal of this task is to implement more standard functions in the STEP framework.

Currently, there are these functions:

  • print: prints something to StdOut
  • println: same as print, but appends an OS-dependent new line at the end
  • readline: reads from StdIn until a new line is read
  • typename: returns a string containing the type name of a variable (number, string, null, etc)
  • parse: converts between different built-in types
  • jsonDecode/jsonEncode: de-/encodes STEP types to and from JSON

The language could benefit greatly by providing more functions to manipulate and work with the various data types. Some of these functions include:

Proposed functions

All proposed functions are categorized into the following categories:

  • mutating: functions that mutate the given subject
  • pure: functions that don't mutate the given subject
  • converting: functions that convert the given subject to another type
  • other: any functions that do not fit in the other categories

Their category defines the naming of the function:

  • do prefix for mutating functions
  • no prefix for pure functions
  • to and from prefixes for converting functions
  • custom prefixes for other functions

Mutating functions

  • #38
    • doAdd: Adds the given element to the end of the list.
    • doRemove: Removes the first occurrence of the given element from the list.
    • doPop: Removes the last element from the list and returns it.
    • doShift: Removes the first element from the list and returns it.
    • doUnshift: Adds the given element to the front of the list.
    • doRemoveAt: Removes the element at the given index/key from a list/map.
    • doInsertAt: Inserts the given element at the given index in the list.
    • doSwap: Swaps the elements at the given indices in a list or the values at the given keys in a map.

Pure functions

  • #32
  • #24
  • #62
    • indexOf: Returns the index/key of the first occurrence of search in the given string/list/map.
    • contains: Returns true if the string/list/map contains the given value.
  • #65
    • startsWith: Returns true if a string starts with the given value.
    • endsWith: Returns true if a string ends with the given value.
  • #67
    • converted: Returns a new list with the results of calling the given function on each element in the given list.
    • filtered: Returns a new list with all elements in the given list that pass the given predicate.
    • reversed: Returns a new list/string with the elements/characters reversed.
    • sorted: Sorts the elements in the given list using the given comparison function and returns a new list.
    • compareTo: Compares two values and returns a value indicating whether one is less than, equal to or greater than the other.
  • #69
    • sin, cos, tan: Returns the sine/cosine/tangent of the given number.
    • min, max: Returns the minimum/maximum of the given number and value.
    • clamp: Returns the given number clamped between the given minimum and maximum.
    • random: Returns a random number between the given minimum and maximum.
    • interpolate: Returns the linear interpolation of the given minimum and maximum by the given delta.
    • abs: Returns the absolute value of the given number.
    • floor: Returns the floor of the given number.
    • ceil: Returns the ceiling of the given number.
    • round: Returns the rounded value of the given number.
    • sqrt: Returns the square root of the given number.
    • global variables:
      • pi: the ratio of the circumference of a circle to its diameter
      • e: natural logarithmic base
  • #71
    • print: Prints the given subject to StdOut.
    • println: Prints the given subject to StdOut and appends a new line.
    • readline: Reads a line from StdIn and returns it.
    • read: Reads a single character from StdIn and returns it.
  • #73
  • #40

Converting functions

  • #42
  • #45
  • #49
    • toJson (previously jsonEncode): Converts the given value to a JSON string.
    • fromJson (previously jsonDecode): Converts the given JSON string to a STEP type.
    • toTypeName (previously typename): Returns the type name of the given subject as a string.
  • #52
  • #54
  • #56
  • #58

Other functions

  • #36
    • fileRead: Reads a file
    • fileExists: Checks if the given file exists.
    • fileDelete: Deletes the given file.
    • fileWrite: Writes a string to a given file.

Removed functions

Documentation

All new functions need documentation.
Each function shall get its own Markdown file in the StepLang.Wiki\Functions folder.

It should include a description, a synopsis of the arguments and what is returned.
Any errors or exceptions specific for this function should also be included (or at least references to the error description).

HTTP Client

STEP is lacking the ability to request data from web APIs using HTTP.

This task intends to add at least some basic functions for making HTTP requests and handling their results.

I'd propose a fetch function, like the Javascript function, taking a url and a map of options, returning the response body as a string or null if the request failed.

Make `run` command default command if no other is given

Going through the steps of the "how to get started" page made me realize its not intuitive to have to type run everytime I want to run a file.
Also, I didn't read the run at first and ran the exe without run and it gave me an "unknown command" error, which is not a good first impression.

It's cumbersome and CLIs like php.exe just run the file by default, which I think makes more sense.
It should just work.

Better tokenizing/parsing error feedback

Currently, there is no way to tell where in a given program the error occurred.
This can be mitigated by saving position values in the tokens and then using the additional information to enrich the error message. Additionally, all the exceptions thrown should be reviewed and custom types might need to be created.

`throw` statements

Sometimes, programmers may want the ability to throw errors and handle them further up in the callstack or even forward the error to the user.

I'd not introduce types for this, so throw would accept anything as an argument.

Introducing a way to throw things might also require a way to catch things. So additionally, a try/catch statement might be needed as well.

Possible designs

The "classic":

try {
	throw "Nope"
} catch (string error) {
	println("Caught: ", error)
}

Using local "panic-calm-callback":

{
	calm = (string error) {
		println("Caught: ", error)
	}

	if (1 == 2) {
		// uses local "calm" function to handle the panic
		// also functions like a return, so no code after is executed
		panic "I broke math"
	} else {
		println("everything fine")
	}
}

// a panic outside of a code block without a global calm handler will trigger a runtime halt
panic "Don't know what to do"

Or like swift:

string contents
do {
    contents = try thisWillThrow(data)
} catch(string error) {
    contents = error
}

function thisWillThrow = () {
    throw "Told ya"
}

Or maybe functional:

string value = try(() {
    return thisWillThrow(data)
}, (string error) {
    println("caught error ", error)

    return "error"
})

Better handling for text

I stumbled upon this article, which discusses how strings are represented using encoding, code points and graphemes: https://tonsky.me/blog/unicode/

To make STEP more accessible, I think we should change how certain functions handle string values, to work with graphemes instead of bytes.

The functions that need to respect graphemes include:

  • length
  • substring
  • indexOf
  • contains
  • startsWith
  • endsWith
  • compareTo
  • reversed
  • index operator str[idx]

Nullable types

null is already a part of the language and many languages have nullable types.

Explicit support for nullable types also opens up the possibility for less error prone code as variables explicitly need to allow null to be assigned to them.

Nullable type declarations might look like this:

string? a = "hello"
string? b = null

number? n = null

list? l = null

Move license to its own file

Moving the license file out of the README.md to its own LICENSE.md allows tools like GitHub to parse it and display it on the project homepage.

Framework functions for testing

Functions to benchmark certain functions or algorithms could be beneficial, say, for encouraging friendly competition between students.

Additionally, functions to test certain expectations can be used to write tests.


This issue is now an umbrella issue for all the todos emerging from it:

  • sleep function
    • sleeps for the given amount of milliseconds
  • assert function
    • tests the given condition and writes a message to STDERR if it fails
  • timestamp function
    • returns the current UNIX timestamp as a high-precision number
  • test function
    • accepts a name and a callback and produces output based on errors encountered running the callback
    • the interpreter could output a summary of all test calls inside a given file (only with a --test option)
    • additionally, the interpreter could keep track of the statements executed to generate coverage data (only with a --cover option)
  • benchmark functions
    • accepts a callback whose execution time will be measured and the result written to STDOUT
  • logInfo, logWarning, logError function
    • same as println but adds a timestamp and the level in front of the message (and logError, maybe logWarning, write to STDERR instead of STDOUT)

Ability to import/export functions

Description

Currently, all the code to run a .step file must be included in the file itself. An exception are the framework functions (readline, println, etc).

In order for others to be able to share and reuse code, a way to import functions from other files is needed.

Justification

One obvious drawback is that it makes the language more complex in general.
Depending on the chosen design, additional keywords may be needed.

On the other hand it allows programmers to explore the widely accepted concept of code splitting.
Not only on a function-by-function basis, but also on a higher level, allowing more complex programs.

As many other languages also use some sort of import structure, STEP would further allow novice programmers to get used to this concept.

Design

Possible implementations could look like the following:

Explicit file imports

Imported files are expected to be found at the relative paths to the importing file.

import "utils/helpers.step"

string connectionString = getConnectionString()

This could also allow glob patterns to be used:

import "loggers/*.step"

logInfo("something important")
logError("this error has occurred: ", EOL, "some error")

Implicit file imports

string connectionString = utils.helpers.getConnectionString()

utils.helpers.<func> would then be converted to a path (utils/helpers.step) and a function with the name of <func> is expected to be defined in the file.

logger.info.println("information log")
logger.error.println("an error occurred: ", "error description")

This would also open the possibility to "invokable" files.
The top level statements in a file could be interpreted as the function body:

calc.step

number a = parse("number", args[0])
number b = parse("number", args[1])
number c = parse("number", args[2])

return c * (a + b) / b

main.step

number a = 5
number b = 12.5
number c = parse("number", readline())

number result = calc(a, b, c)
// or alternatively:
number result = calc([a, b, c])
// or
number result = calc.invoke([a, b, c])


println("Result: ", result)

With explicit exports

Explicitly exporting members gives the programmer more control over what is exposed from their code.
This aligns with the goal of providing reusability as internal/helper methods can be hidden from the public API.

calc.step

function minmax = (number a, number b, number c) {
    if (c < a) {
        return a
    }

    if (c > b) {
        return b
    }

    return c
}

function doCalc = (string x, string y) {
    number xNum = parse("number", x)
    number yNum = parse("number", y)

    return minmax(0, 10, xNum) * minmax(10, 20, yNum)
}

export doCalc
// or, to re-use existing keywords:
return doCalc

main.step

// doesn't import minmax from calc.step
import "calc.step"

println(doCalc(readline(), readline()))

All combined

The above proposals don't exactly need to be implemented on their own. Another approach would be a combination of all of them:

calc.step

function minmax = (number a, number b, number c) {
    if (c < a) {
        return a
    }

    if (c > b) {
        return b
    }

    return c
}

function doCalc = (string x, string y) {
    number xNum = parse("number", x)
    number yNum = parse("number", y)

    return minmax(0, 10, xNum) * minmax(10, 20, yNum)
}

export doCalc

math.step

number pi = 3.141592

function cube = (number a) {
    return a ^ 3;
}

export pi
export cube

main.step

// explicitly import math.step
import 'math.step'

// use members from math.step
println(cube(pi))

// implicitly import calc.step (only doCalc is visible)
println(calc.doCalc(readline(), readline()))

With import aliases

import("math.step", math)
import("calc.step", calc)

println("3 cubed: ", math.cube(3))
println(calc.doCalc("123", "456"))

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    ๐Ÿ–– Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. ๐Ÿ“Š๐Ÿ“ˆ๐ŸŽ‰

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google โค๏ธ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.