Skip to content

Commit

Permalink
func: add time, random and http to larder
Browse files Browse the repository at this point in the history
  • Loading branch information
anirudhgray committed Oct 31, 2024
1 parent b73022b commit 00a48f2
Show file tree
Hide file tree
Showing 9 changed files with 260 additions and 24 deletions.
7 changes: 5 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -441,10 +441,13 @@ Tahini comes with a growing standard library, called [the `larder`](./tahini/app

Here are some of the modules and functions available in the `larder`:

- `larder/math` - Mathematical functions like `sqrt`, `pow`, `sin` etc.
- `larder/string` - String manipulation functions like `split`, `join` etc.
- `larder/math` - Mathematical functions like `sqrt`, `pow`, `sin`, `round` etc.
- `larder/string` - String manipulation functions like `split`, `join`, `replace` etc.
- `larder/io` - File I/O functions like `readFile`, `writeFile` etc.
- `larder/collections` - Collection functions like `values`, `keys`, `append`, `remove` etc.
- `larder/time` - Time functions like `now`, `format` etc.
- `larder/random` - Random number generation functions like `random`, `randomInt` etc.
- `larder/http` - HTTP request functions like `get` (only `get` for now).

You can import the `larder` modules in your Tahini code using the `scoop` keyword, similar to importing other Tahini files.

Expand Down
21 changes: 0 additions & 21 deletions tahini/app/src/main/java/com/tahini/lang/Interpreter.java
Original file line number Diff line number Diff line change
Expand Up @@ -32,27 +32,6 @@ class BreakException extends RuntimeException {

public Interpreter(boolean repl) {
this.repl = repl;
globals.define("clock", new TahiniCallable() {
@Override
public int arity() {
return 0;
}

@Override
public Object call(Interpreter interpreter, List<Object> arguments) {
return (double) System.currentTimeMillis() / 1000.0;
}

@Override
public String toString() {
return "<native fn>";
}

@Override
public boolean isInternal() {
return false;
}
});
StandardLibrary.addStandardFunctions(environment);
StandardLibrary.addInternalFunctions(environment);
}
Expand Down
115 changes: 115 additions & 0 deletions tahini/app/src/main/java/com/tahini/lang/StandardLibrary.java
Original file line number Diff line number Diff line change
@@ -1,6 +1,10 @@
package com.tahini.lang;

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.net.HttpURLConnection;
import java.net.URL;
import java.nio.charset.StandardCharsets;
import java.nio.file.Files;
import java.nio.file.Path;
Expand All @@ -14,13 +18,124 @@ class StandardLibrary {
public static void addStandardFunctions(Environment globalEnv) {
globalEnv.define("input", new InputFunction());
globalEnv.define("len", new ArrayLengthFunction());
globalEnv.define("clock", new UnixEpochSecondsFunction());
}

public static void addInternalFunctions(Environment globalEnv) {
globalEnv.define("_keys", new HashmapKeysFunction());
globalEnv.define("_values", new HashmapValuesFunction());
globalEnv.define("_read", new FileReadFunction());
globalEnv.define("_write", new FileWriteFunction());
globalEnv.define("_random", new RandomHelperFunction());
globalEnv.define("_http", new HTTPRestFunction());
}
}

class HTTPRestFunction implements TahiniCallable {

@Override
public int arity() {
return 2;
}

@Override
public Object call(Interpreter interpreter, List<Object> args) {
if (args.size() != 2) {
throw new RuntimeError(null, "Expected 2 arguments but got " + args.size() + ".", null);
}
Object urlarg = args.get(0);
if (!(urlarg instanceof String url)) {
throw new RuntimeError(null, "Expected a string url but got " + urlarg + ".", null);
}
Object methodarg = args.get(1);
if (!(methodarg.equals("GET"))) {
throw new RuntimeError(null, "Expected 'GET' but got " + methodarg + ".", null);
}
String response;
try {
response = sendGetRequest(url);
return response;
} catch (IOException e) {
throw new RuntimeError(null, "Error sending HTTP request: " + e.getMessage(), null);
}
}

@Override
public String toString() {
return "<native fn>";
}

@Override
public boolean isInternal() {
return false;
}

private static String sendGetRequest(String apiUrl) throws IOException {
URL url = new URL(apiUrl);
HttpURLConnection connection = (HttpURLConnection) url.openConnection();
connection.setRequestMethod("GET");

int responseCode = connection.getResponseCode();
if (responseCode == HttpURLConnection.HTTP_OK) {
BufferedReader reader = new BufferedReader(new InputStreamReader(connection.getInputStream()));
StringBuilder response = new StringBuilder();
String line;

while ((line = reader.readLine()) != null) {
response.append(line);
}

reader.close();
return response.toString();
} else {
return "Failed to get the API response. Response code: " + responseCode;
}
}
}

class RandomHelperFunction implements TahiniCallable {

@Override
public int arity() {
return 0;
}

@Override
public Object call(Interpreter interpreter, List<Object> arguments) {
return Math.random();
}

@Override
public String toString() {
return "<native fn>";
}

@Override
public boolean isInternal() {
return false;
}
}

class UnixEpochSecondsFunction implements TahiniCallable {

@Override
public int arity() {
return 0;
}

@Override
public Object call(Interpreter interpreter, List<Object> arguments) {
return (double) System.currentTimeMillis() / 1000.0;
}

@Override
public String toString() {
return "<native fn>";
}

@Override
public boolean isInternal() {
return false;
}
}

Expand Down
5 changes: 5 additions & 0 deletions tahini/app/src/main/resources/stdlib/http.tah
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
// Send a GET request to the specified URL and return the response.
fun get(url) {
var response = _http(url, "GET");
return response;
}
5 changes: 5 additions & 0 deletions tahini/app/src/main/resources/stdlib/math.tah
Original file line number Diff line number Diff line change
Expand Up @@ -88,3 +88,8 @@ fun cos(a) {
fun tan(a) {
return sin(a) / cos(a);
}

fun round(float, precision) {
var factor = pow(10, precision);
return ceil(float * factor - 0.5) / factor;
}
11 changes: 11 additions & 0 deletions tahini/app/src/main/resources/stdlib/random.tah
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
scoop "larder/math";

// Random float between 0 and 1
fun random() {
return _random();
}

// Random integer between min and max
fun randomInt(min, max) {
return floor(random() * (max - min + 1) + min);
}
15 changes: 15 additions & 0 deletions tahini/app/src/main/resources/stdlib/string.tah
Original file line number Diff line number Diff line change
Expand Up @@ -23,3 +23,18 @@ fun join(arr, delimiter) {
}
return result;
}

fun replace(string, old, new) {
var result = "";
var start = 0;
var oldLength = len(old);
for (var i = 0; i <= len(string) - oldLength; i = i + 1) {
if (string[i:i + oldLength] == old) {
result = result + string[start:i] + new;
start = i + oldLength;
i = i + oldLength - 1;
}
}
result = result + string[start:len(string)];
return result;
}
89 changes: 89 additions & 0 deletions tahini/app/src/main/resources/stdlib/time.tah
Original file line number Diff line number Diff line change
@@ -0,0 +1,89 @@
// time standard lib funcs
scoop "larder/string" into string;
scoop "larder/math" into math;

// unix epoch in seconds (using the inbuilt clock() function)
fun now() {
return clock();
}

fun isLeapYear(year) {
if (year % 4 == 0) {
if (year % 100 == 0) {
if (year % 400 == 0) {
return true;
} else {
return false;
}
} else {
return true;
}
} else {
return false;
}
}

fun daysInMonth(month, year) {
if (month == 2) {
return isLeapYear(year) ? 29 : 28;
} else if (month == 4 or month == 6 or month == 9 or month == 11) {
return 30;
} else {
return 31;
}
}

// Format a Unix timestamp into a string format "YYYY-MM-DD HH:mm:ss"
fun format(epoch, formatStr) {
var secondsInDay = 86400;
var secondsInYear = 365 * secondsInDay;
var remaining = epoch;

// Calculate the year
var year = 1970;
while (remaining >= secondsInYear) {
remaining = remaining - secondsInYear;
year = year + 1;
secondsInYear = isLeapYear(year) ? 366 * secondsInDay : 365 * secondsInDay;
}

// Calculate the month and day
var month = 1;
while (true) {
var daysInThisMonth = daysInMonth(month, year);
var secondsInThisMonth = daysInThisMonth * secondsInDay;
if (remaining < secondsInThisMonth) {
break;
}
remaining = remaining - secondsInThisMonth;
month = month + 1;
}
var day = 1 + remaining / secondsInDay;
day = math::floor(day);
remaining = remaining % secondsInDay;

// Calculate the hour, minute, and second
var hour = remaining / 3600;
hour = math::floor(hour);
remaining = remaining % 3600;
var minute = remaining / 60;
minute = math::floor(minute);
var second = remaining % 60;
second = math::round(second, 3);

// Replace placeholders in formatStr
var result = formatStr;
result = string::replace(result, "YYYY", year);
result = string::replace(result, "MM", month);
result = string::replace(result, "DD", day);
result = string::replace(result, "HH", hour);
result = string::replace(result, "mm", minute);
result = string::replace(result, "ss", second);

return result;
}

// Convert a Unix timestamp to ISO 8601 format "YYYY-MM-DDTHH:mm:ssZ"
fun toIso(epoch) {
return format(epoch, "YYYY-MM-DDTHH:mm:ssZ");
}
16 changes: 15 additions & 1 deletion test1.tah
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,21 @@ scoop "larder/math" into math;
scoop "larder/collections" into collections;
scoop "larder/string" into string;
scoop "larder/io";
scoop "larder/time" into time;
scoop "larder/random" into random;
scoop "larder/http" into http;

print random::random();
print random::randomInt(3,10);

print http::get("https://jsonplaceholder.typicode.com/posts/1");

var curr = time::now();
print curr;
print time::format(curr, "YYYY-MM-DD HH:mm");
print time::toIso(curr);

print string::replace("hello world cello", "llo", 44);

print math::sin(0.5);

Expand All @@ -26,4 +41,3 @@ var l = string::split("hello. world", ". ");
print len(l);
print l[1];
print string::join(l, " | ");
writeFile("test1.tah","//okllll");

0 comments on commit 00a48f2

Please sign in to comment.