This is a read-only snapshot of the ComputerCraft forums, taken in April 2020.
ElvishJerricco's profile picture

Project NewLife v1.1 - Breathing New Life into CraftOS - New: LASM

Started by ElvishJerricco, 23 May 2013 - 12:28 AM
ElvishJerricco #1
Posted 23 May 2013 - 02:28 AM
Project NewLife



Project NewLife is a suite of applications and APIs intended to make the CraftOS experience better. First, it should be known that Project NewLife is not meant to be an operating system. Development began on NewLife when capabilities were needed that CraftOS alone couldn't provide. Any program written for CraftOS will still work perfectly under NewLife. But NewLife adds many capabilities that were much more difficult before.

Overview

CraftOS brings to the table some useful APIs like textutils, the shell API, and even a rednet API. Project NewLife adds to this with these features and more.
  • A new shell
  • Multitasking
  • A UNIX-like pipeline
  • A lua to bytecode compiler
  • Running bytecode compiled lua programs
  • A command line tool for editing the path
  • Shell scripts
  • Argument processing API
  • JSON API
  • Extended string and table libraries
  • File extension based custom file loading for APIs
  • Virtual files
  • Daemons
  • A github repo downloader
  • LASM - CC's first alternate programming language.
Karma.lua

Understanding how to take advantage of the NewLife system requires understanding of its core. This is called karma.lua. When NewLife loads, the file /NewLife/karma.lua is the first thing that's run after the CraftOS shell is killed. The purpose of karma.lua is to run all the karma extensions. Extension programs can be found in /NewLife/ext. Karma loads these files with no protections. They all read and write to the _G table as their environment.

Writing an extension
SpoilerIf you want to add primitive level APIs that are loaded at runtime and cannot be unloaded by a third party program, you will need to write a Karma extension.

First create a file in /NewLife/ext. This file will house all of your code. Also note that any functions or variables declared globally will be accessible to any other code run at any time in the system. So if you want to keep something private to your file, make sure to use the local keyword. Also, add your extension to karma.lson.

There is an exception to that for the init function though. If you declare an init function as global, it does set _G["init"] to your function. But after your file is loaded, karma.lua takes that value and keeps it. Then it wipes _G["init"] so that it can get all the init functions from all the files. Then once all the extensions have been loaded, all of the init functions are called, with the config table from karma.lson in /NewLife/etc passed as an argument.

When to write an extension
Why write an unprotected extension when you could just write an API? There is no good reason unless you are modifying existing APIs or you're writing functions which are intended to be a primitive type of function. For example, the loadlibs.lua extension creates a function called loadAPI. It differs from os.loadAPI in that it returns the API instead of setting a global variable to the API. It's meant to be a primitive for getting code, and is low level. So it is an extension.

Object Oriented Programming

One of the Karma extensions is called NLClass.lua. This extension adds a system-wide OOP API. The following is an explanation on how to use it.

SpoilerClasses can either be declared in functions or in files with a .nlclass extension which are then loaded via loadAPI.


function MyClass()
	function test()
		print('test')
	end
end

local obj = new(MyClass).init()
obj.test()

This will print "test." Note that MyClass is not called directly. Any variables declared globally in a class will not become global. Instead, they will become publicly available in the object returned by new(). That's why the function 'test' is not made global, but is instead a method in the object. Also, every class implicitly has an init value, which is often overridden with new parameters for initialization. Init should always return the object (by using "return this"), so that you can call new().init() in one line.

	
function MyClass()
	local a
	function init(_a, _c)
		super.init()
		a = _a
		c = _c
	end
end

local obj = new(MyClass).init(3, 4)
print(obj.a)
print(obj.c)

The first print statement will not output anything. The second one will print 4. The "a" variable in obj is private because of the local keyword. But "b" is publicly available because it was defined in init as if it were a global.

Also note that no function has to be called for NLClass.lua to use MyClass as a class. But that's not true in the case of subclassing.


function MyClass()
	function init()
		print("MyClass")
	end
end

function MySubClass()
	function init()
		super.init()
		print("MySubClass")
	end
end
class(MySubClass, MyClass)

local obj = new(MySubClass).init()

This will print


MyClass
MySubClass

The super instance variable in a class works as expected, with multiple inheritence supported.

And finally, setting up a class and its setting its superclass from within the class file:


function MyClass()
	function __setupClass()
		class(MyClass, SuperClass)
	end
end

When an object of MyClass is created, if that class hasn't yet had its __setupClass() called, it will be called before creating the object. This allows you to set your superclass from within the class.

NEW!
There's a class built into the system called NLObject that is the superclass of any class instantiated, even when not defined as the superclass. Only built in methods are init(), which does nothing notable, and instanceof(class), which returns true if the object is an instance of class

Loading APIs and File Type Loaders

There's some new functionality alongside os.loadAPI now. Directories can be loaded recursively, APIs can be loaded and returned locally, and NLClasses can be kept in files instead of functions.

SpoilerFirst, it's important to know how APIs handle their file extensions now. In /NewLife/ldr, you will find several file type loaders. When loading an API, if it has a file type n, and there exists a file /NewLife/ldr/n.lua, that loader code will be used to load the file, and the file extension will be stripped from the API name.


-- MyApi.lua
function test()
	print('test')
end


-- MyProgram.lua
os.loadAPI('MyApi.lua')
MyApi.test()

Even though MyApi has the .lua extension, that is now stripped when I try to access the loaded API by name.

Any file without a known file extension will be loaded with the /NewLife/ldr/lua.lua loader. The lua loader takes all the code and runs it into an API table, as we are used to in standard CraftOS. But there is also a loader for NLClasses with the file type .nlclass.


-- MyClass.nlclass
function init()
	print('init')
end


-- MyProgram.lua
os.loadAPI('MyClass.nlclass')
local obj = new(MyClass).init()

This will print "init" because MyClass is loaded as a class, and the .nlclass extension is stripped from the name.

The other built in types are .json and .txtutl. A .json file will be decoded as json text, and a .txtutl file will be decoded with textutils.unserialize().

Writing a loader is easy. Let's say we want to write a loader for the file type .image which treated each line as a line on the screen. Each character in the line is a hex value 0-15 representing the color to display. The loaded API would be a two dimensional table.


--/NewLife/ldr/image.lua
local path, api = ...	-- path is the file we are being told to load
			-- api is the table that we can either put our data in,
			-- or use as the environment (for stuff like functions)
local file, err = fs.open(path, "r")
assert(file, err)
local count = 1
for line in file.readLine do
	tLine = {}
	for i=1, #line do
		tLine[i] = 2 ^ tonumber(line:sub(i,i), 16)	-- use hexadecimal
								-- do 2 ^ char to get the colors api color
	end
	api[count] = tLine
	count = count + 1
end

return api


You must return the value you want to be given as the API. The api table passed in is typically what you would use as either the place to load into, or the environment to set your functions to. Also note that you are allowed to error() and assert() in here. IT SHOULD BE EXPECTED THAT LOADING APIS WILL FAIL

APIs can be loaded locally now. If you don't want to load a file system wide, you can use the function loadAPI. It's not os.loadAPI. It's just loadAPI. A global function.


-- MyApi.lua
function test()
	print('test')
end


-- MyProgram.lua
local api = loadAPI("MyApi.lua")
api.test()

This is valid. And MyApi will not be present in the global scope. The API was loaded locally. This is why it should be expected that loading an API will fail. Although os.loadAPI() checks for errors and returns false if there was one, loadAPI does not do this. It expects that you will surround the loadAPI call in a pcall() and check yourself. Similar to how java often requires you to surround things in a try-catch block.

And finally, directories can be loaded recursively. Take the following folder structure.


MyApi
|-First.lua
|-Second.nlclass
|-MoreApi
  |-Third.lua
  |-Last.nlclass


os.loadAPI('MyApi')
MyApi.First.test()
local sec = new(MyApi.Second).init()
MyApi.MoreApi.Third.func()
local las = new(MyApi.MoreApi.Last).init()

The loaded API is a table with all the APIs inside the directory loaded.

Multitasking

NewLife functions on processes. Theres an NLClass loaded at boot called Process which is used to create a process from either a function or a file.

Spoiler

local procEnv = setmetatable({}, {__index = getfenv()})
local proc = new(Process).init("filename.lua", procEnv, stdin, stdout, ... )
while proc.status() ~= "dead" do
	os.pullEvent()
end

This loads a file "filename.lua" into a process and waits for that process to be complete. When a process dies, it create an event called "process_death" which is why we don't have to worry about os.pullEvent() stalling. stdin and stdout are meant to be the IO pipeline files.

The Pipeline
Every process has an input file and an output file. Most processes run with stdin (standard in) and stdout (standard out). The IO files don't have to be actual files on disk. The input file just needs to be a table with a "readLine" function, and the output file just needs to be a table with a "write" function. stdin points to the current process's input file. stdout points to the process's output file.

When a process iterates (goes one cycle until it yields the coroutine), the global functions read and write redirect to the IO files of the process. This means that when print is called, print calls write, which calls the output file of the process. So if you had the output file being an actual file on disk, then printing would just write to that file.

The custom shell in NewLife (called ClamShell), supports using these IO capabilities in a way similar to the UNIX pipeline.


ls > testFile

This command in ClamShell would take the output of the ls program and direct it to the file "testFile". But if testFile were actually a program, it would continually read from the ls output until there was nothing left to read from. So if you run ls > testFile once, and this creates a file with the output of ls, you cannot run the same command again. ClamShell would try to run the testFile from the previous running of the command as a program and redirect its input to the ls output. Obviously this wouldn't work.

The solution is that you can force ClamShell to treat testFile as a file instead of a command.


ls >: testFile

If you have a colon on either side of the pipe symbol ( > ), the command on the same side will be forced to be treated as a file.

There is a program built into NewLife called "type". Type takes input until read() returns nil, and prints all the read text. This is primarily used in the pipeline.


someFile :> type

That code will read someFile and print it to the screen. This allows some basic logging capabilities. For example,


ls >: somefile :> type

ls outputs to the file. The file outputs to type. Type outputs to the screen. So all the data is saved in somefile, and printed on the screen.

There's also a program called "ps" which lists running processes and lets you kill any of them.

And finally, the last program I'll talk about here is echo. Echo takes its arguments and simply prints them to the output. This is useful for simple stuff like "echo "testing!" > myfile" because you can save text to a file quite easily.

Multiple File Programming

In CraftOS, there's no good way to use multiple files in a program. Project NewLife allows the creation of processes from directories of code.

Spoiler

MyProgram
|-SomeClass.nlclass
|-main.coroutine


-- SomeClass.nlclass
function init()
	print("MyProgram!")
end


-- main.coroutine
new(SomeClass).init()

In the shell, you could use the MyProgram directory as a valid program. The files are all actually loaded via the loadAPI() function, so they all get run. But once they're all loaded, the main.coroutine file, which was loaded as a coroutine, will be resumed with the arguments being the process arguments. In this case, main.coroutine just creates an instance of SomeClass, which prints "MyProgram!"

This capability allows for much more complex projects to be handled much more elegantly.

Daemons and Virtual Files

SpoilerThere is a subclass of Process called Daemon. Daemon's constructor simply requires the path to the file to run, and the path to the folder where the log file should be held. The Daemon class automatically handles setting the stdin and stdout files for the process. There is no standard input, and the output is the log file. At boot time, any programs stored in /NewLife/srv will be started as daemons.

Along with Daemons are virtual files. The fs API has been modified to allow the creation of files that don't write to the disk, but instead talk to a process.


-- My daemons main file
function main()
	fs.createVirtualFile("/NewLife/dev/test", {	w=writeHandle, wb=writeBytesHandle,
							a=appendHandle, ab=appendBytesHandle,
							r=readHandle, rb=readBytesHandle})
end

Creating a virtual file expects you to give a handle for all the types of file modes that you expect to be used. These handles must provide all the functions used by typical file system handles. Everything else on the computer will see this virtual file as nothing more than a normal file. Therefore, it is imperative that your file handle functions do not crash. If they crash, the process trying to use the file crashes. The expected way to deal with this is that none of the logic occurs in the file handle functions. All the logic is handled by your process, data is shared between the handles and the process, and the handles alert your process that logic needs to occur via an os.queueEvent() call.

The purpose of /NewLife/dev is to be a folder for virtual files to exist. This is where it might be smart to keep your files.

Smaller Features

Spoilerstartup.lua
When ClamShell starts up, it does what the CraftOS shell does in that it looks for a file to run. But instead of running startup (that would not go well), it runs startup.lua.

Compiling
For those who wish to compile their lua code, there is a program called luac which can take a file and compile it to lua bytecode. The function "loadfile" has been modified to read files by bytes and load the string as code, so anything that loads programs through loadfile can run both text based lua programs and bytecode ones.

Extended string and table libraries

SpoilerThe string library has a "split" function added to it.


function string.split(str, pat, maxNb)
@param str				The string to split
@param pat				The pattern to use as the delimiter
@param maxNb				The max number of splits to make
@return					A table of the split values

The table library has several functions for inverting, clearing, and copying tables.


function table.copy(t, recursiveMT)
@param t				The table to copy
@param recursiveMT			Whether the metatable should be copied recursively or not
@return					A copy of t


function table.recursiveCopy(t, recursiveMT)
@param t				The table to copy
@param recursiveMT			Whether the metatable should be copied recursively or not
@return					A copy of t, with all table values also copied


function table.clear(t)
@param t				The table to clear
@purpose				Empty all values out of a table


function table.invert(t)
@param t				The table to invert
@return					A table whose keys are t's values, and whose values are t's keys


function table.arrayCopy(src, pos1, dest, pos2, len)
@param src				The source tables
@param pos1				The position in src to start copying from
@param dest				The destination table
@param pos2				The position in dest to start copying to
@param len				The number of entries to copy.
@purpose				To copy a section of data from src to dest


function table.arrayCopyRecursive(src, pos1, dest, pos2, len)
@param src				The source tables
@param pos1				The position in src to start copying from
@param dest				The destination table
@param pos2				The position in dest to start copying to
@param len				The number of entries to copy.
@purpose				To copy a section of data from src to dest, and also recursively copy any table entries being copied

JSON API
A simple API for going between lua values and JSON text.


function json.decode(text)
@param text				The text to turn into a lua value
@return					The lua value


function json.encode(val)
@param val				The value to turn into JSON
@return					JSON


function json.encodePretty(val)
@param val				The value to turn into JSON
@return					JSON formatted to be pretty

A path editing program
NewLife adds a program called path which can display the current path, and edit it.

path add /someplace
path remove /someplace

A shell script program
cs is a program that takes a file and runs each line as a shell script. It's not complicated but much more is planned for it.

A github repo downloader
gh downloads github repos. Use the command like this:
gh -user {username} -repo {repo name} {directory to save}

You can get Project NewLife by downloading it from its github repo. I do plan to have an automatic downloader and installer, as well as an updater, but for now this is fine.

As requested, a quick installation guide.

Download the entire repo as a zip, extract the zip, and go into the Project-NewLife folder. Put the two files and the folder in the root folder of your computer. /startup.lua is optional, since it's intended to be edited by the user.

Changelog:
Spoilerv1.1
  • Added: LASM; An assembly language for Lua bytecode
  • Added: NLObject. The superclass of EVERYTHING
  • Changed: NLClass no longer calls init() automatically for you. This allows selected initializers.
  • Changed: Reworked the JSON encoder. Much simpler.
  • Changed: txtutl file extension changed to lson

v1.0.2
  • Added: .coroutine extension. Loads the file as a coroutine.
  • Changed: Multi-file programming no longer uses main.lua with a main function. Instead, use main.coroutine, which will be resumed on launch with the arguments.

v1.0.1
  • Added: Virtual files
  • Added: File extension loaders
  • Added: Support for loading JSON and text serialized by textutils as APIs
  • Added: Support for loading txt files as text in APIs
  • Added: A daemon class
  • Added: A github repo downloader
  • Changed: stdin/stdout now point to the current process's in and out, rather than the keyboard and terminal.
  • Changed: os.queueEvent now supports queueing event with tables as parameters
  • Changed: The process.lua karma extension is now an API in /NewLife/lib. No more annoying global functions
  • Changed: os.run now uses Processes
  • Removed: FileStream.nlclass. Wasn't necessary.

v1.0
  • Initial release
Zudo #2
Posted 23 May 2013 - 03:01 AM
This would be cool… I will look at it after school.
Zudo #3
Posted 23 May 2013 - 03:03 AM
And before you ask, I am not in school. I am on my raspberry pi so no minecraft. My PC is virus scanning…
Shnupbups #4
Posted 23 May 2013 - 03:04 AM
Cool! Will try it out when I'm on CC next.
nutcase84 #5
Posted 23 May 2013 - 07:16 AM
And before you ask, I am not in school. I am on my raspberry pi so no minecraft. My PC is virus scanning…

CC-EMU.
dsuser97 #6
Posted 27 May 2013 - 02:06 PM
SpoilerNot sure about this but when I trie to load this project into Minecraft by putting it into mods/ProjectNewLife/lua/rom/ it gives me a parsing error.
Spoiler2013-05-27 19:57:35 [SEVERE] [ForgeModLoader] There was a problem reading the file D:\Documentaire\Spiele\Minecraft\instances\CCTest\minecraft\mods\ProjectNewLife\lua\rom\NewLife\bin\clamshell\ClamShell.nlclass - probably this is a corrupt file
cpw.mods.fml.common.LoaderException: java.lang.IllegalArgumentException
at cpw.mods.fml.common.discovery.asm.ASMModParser.<init>(ASMModParser.java:60)
at cpw.mods.fml.common.discovery.DirectoryDiscoverer.exploreFileSystem(DirectoryDiscoverer.java:99)
at cpw.mods.fml.common.discovery.DirectoryDiscoverer.exploreFileSystem(DirectoryDiscoverer.java:88)
at cpw.mods.fml.common.discovery.DirectoryDiscoverer.exploreFileSystem(DirectoryDiscoverer.java:88)
at cpw.mods.fml.common.discovery.DirectoryDiscoverer.exploreFileSystem(DirectoryDiscoverer.java:88)
at cpw.mods.fml.common.discovery.DirectoryDiscoverer.exploreFileSystem(DirectoryDiscoverer.java:88)
at cpw.mods.fml.common.discovery.DirectoryDiscoverer.exploreFileSystem(DirectoryDiscoverer.java:88)
at cpw.mods.fml.common.discovery.DirectoryDiscoverer.discover(DirectoryDiscoverer.java:52)
at cpw.mods.fml.common.discovery.ContainerType.findMods(ContainerType.java:42)
at cpw.mods.fml.common.discovery.ModCandidate.explore(ModCandidate.java:64)
at cpw.mods.fml.common.discovery.ModDiscoverer.identifyMods(ModDiscoverer.java:115)
at cpw.mods.fml.common.Loader.identifyMods(Loader.java:347)
at cpw.mods.fml.common.Loader.loadMods(Loader.java:479)
at cpw.mods.fml.client.FMLClientHandler.beginMinecraftLoading(FMLClientHandler.java:160)
at net.minecraft.client.Minecraft.func_71384_a(Minecraft.java:411)
at net.minecraft.client.MinecraftAppletImpl.func_71384_a(SourceFile:56)
at net.minecraft.client.Minecraft.run(Minecraft.java:733)
at java.lang.Thread.run(Unknown Source)
Caused by: java.lang.IllegalArgumentException
at org.objectweb.asm.ClassReader.<init>(Unknown Source)
at org.objectweb.asm.ClassReader.<init>(Unknown Source)
at org.objectweb.asm.ClassReader.<init>(Unknown Source)
at cpw.mods.fml.common.discovery.asm.ASMModParser.<init>(ASMModParser.java:54)
… 17 more
As far as I understand this i think FML tries to parse the file as a Java class file a fails in the progress.
The only thing I can see at the moment to change this would be to change this file-ending to like "classnl"

Otherwise, i might just put them somwhere in the jar, so it's not loaded by FML but that would not be very comfortable for using with other Mods.
EDIT: didn't think about putting it directly onto a computer, my fault. Works fine.
You might want to add at least some sort of installation guide.

But anyway, I like the Idea of this API to provide some useful additional features.
I might try out to program some sort of OS in the future, and if you agree, I will maybe put this into it.
UMayBleed #7
Posted 27 May 2013 - 05:00 PM
Oh my god! This is just what i've always wanted! Lua to be more like Java.
ElvishJerricco #8
Posted 27 May 2013 - 08:07 PM
SpoilerNot sure about this but when I trie to load this project into Minecraft by putting it into mods/ProjectNewLife/lua/rom/ it gives me a parsing error.
Spoiler2013-05-27 19:57:35 [SEVERE] [ForgeModLoader] There was a problem reading the file D:\Documentaire\Spiele\Minecraft\instances\CCTest\minecraft\mods\ProjectNewLife\lua\rom\NewLife\bin\clamshell\ClamShell.nlclass - probably this is a corrupt file
cpw.mods.fml.common.LoaderException: java.lang.IllegalArgumentException
at cpw.mods.fml.common.discovery.asm.ASMModParser.<init>(ASMModParser.java:60)
at cpw.mods.fml.common.discovery.DirectoryDiscoverer.exploreFileSystem(DirectoryDiscoverer.java:99)
at cpw.mods.fml.common.discovery.DirectoryDiscoverer.exploreFileSystem(DirectoryDiscoverer.java:88)
at cpw.mods.fml.common.discovery.DirectoryDiscoverer.exploreFileSystem(DirectoryDiscoverer.java:88)
at cpw.mods.fml.common.discovery.DirectoryDiscoverer.exploreFileSystem(DirectoryDiscoverer.java:88)
at cpw.mods.fml.common.discovery.DirectoryDiscoverer.exploreFileSystem(DirectoryDiscoverer.java:88)
at cpw.mods.fml.common.discovery.DirectoryDiscoverer.exploreFileSystem(DirectoryDiscoverer.java:88)
at cpw.mods.fml.common.discovery.DirectoryDiscoverer.discover(DirectoryDiscoverer.java:52)
at cpw.mods.fml.common.discovery.ContainerType.findMods(ContainerType.java:42)
at cpw.mods.fml.common.discovery.ModCandidate.explore(ModCandidate.java:64)
at cpw.mods.fml.common.discovery.ModDiscoverer.identifyMods(ModDiscoverer.java:115)
at cpw.mods.fml.common.Loader.identifyMods(Loader.java:347)
at cpw.mods.fml.common.Loader.loadMods(Loader.java:479)
at cpw.mods.fml.client.FMLClientHandler.beginMinecraftLoading(FMLClientHandler.java:160)
at net.minecraft.client.Minecraft.func_71384_a(Minecraft.java:411)
at net.minecraft.client.MinecraftAppletImpl.func_71384_a(SourceFile:56)
at net.minecraft.client.Minecraft.run(Minecraft.java:733)
at java.lang.Thread.run(Unknown Source)
Caused by: java.lang.IllegalArgumentException
at org.objectweb.asm.ClassReader.<init>(Unknown Source)
at org.objectweb.asm.ClassReader.<init>(Unknown Source)
at org.objectweb.asm.ClassReader.<init>(Unknown Source)
at cpw.mods.fml.common.discovery.asm.ASMModParser.<init>(ASMModParser.java:54)
… 17 more
As far as I understand this i think FML tries to parse the file as a Java class file a fails in the progress.
The only thing I can see at the moment to change this would be to change this file-ending to like "classnl"

Otherwise, i might just put them somwhere in the jar, so it's not loaded by FML but that would not be very comfortable for using with other Mods.
EDIT: didn't think about putting it directly onto a computer, my fault. Works fine.
You might want to add at least some sort of installation guide.

But anyway, I like the Idea of this API to provide some useful additional features.
I might try out to program some sort of OS in the future, and if you agree, I will maybe put this into it.

For people wanting to build an OS, I think Project NewLife has more than enough APIs and features to make that task much easier. I'm nearing completion of version 1.1, so when I get to the release cycle for that I'll put a loose license up.

And just FYI for people, 1.1 implements some minor revisions and an interprocess communication system. And the main feature is a powerful, secure networking API that uses the interprocess communication.

The plan for 1.2 will hopefully be to include a graphics library. And if I can get permission, I'll include NPaintPro and GameUtils so that their image file formats can be the standard on the system.

Oh my god! This is just what i've always wanted! Lua to be more like Java.

NLClass was actually inspired by JavaScript's function based OOP. That's why classes are written inside of functions (or files) instead of tables.
Shnupbups #9
Posted 28 May 2013 - 02:54 AM
Just a small bit of input: the string.split should return an unpacked version of the table (so it returns each of the strings, rather than a table of the strings).

You can do this with:

unpack(tableName) --# tableName is, of course, the table name.
ElvishJerricco #10
Posted 28 May 2013 - 08:17 PM
Just a small bit of input: the string.split should return an unpacked version of the table (so it returns each of the strings, rather than a table of the strings).

You can do this with:

unpack(tableName) --# tableName is, of course, the table name.

Is there some standard dictating that that's how it should be? Or is that just your preference? I did think about doing it that way. Ultimately I decided that if they want to split a string up, it's unlikely that they only want to use a series starting at the beginning, so why have them pack something that was just unpacked?
Symmetryc #11
Posted 29 May 2013 - 11:03 PM
I think what Shnup was saying was that instead of doing this:

local a = "Hello Person 2413"
local tMsg = string.split(a, "Person", 1)
print(tMsg[1].." is the greeting")
print(tMsg[2].." is the number")
Most people would do this:

local b = "Hello Person 13213"
local greet, num = string.split(b, "Person", 1)
print(greet.. " is the greeting")
print(num.. " is the number")
Sort of how os.pullEvent() returns several params rather than a single table which contains all of the params.
ElvishJerricco #12
Posted 29 May 2013 - 11:18 PM
I think what Shnup was saying was that instead of doing this:

local a = "Hello Person 2413"
local tMsg = string.split(a, "Person", 1)
print(tMsg[1].." is the greeting")
print(tMsg[2].." is the number")
Most people would do this:

local b = "Hello Person 13213"
local greet, num = string.split(b, "Person", 1)
print(greet.. " is the greeting")
print(num.. " is the number")
Sort of how os.pullEvent() returns several params rather than a single table which contains all of the params.

I understand that. But if you do it that way, you can only get a series starting with the first entry. For example, let's say you used "\n" as the delimiter. string.split would return an array of all the lines. What you're suggesting limits the user of the function to only keeping a series of the lines starting with the first one, and going till they stop naming variables. Unless of course you pack all the results of the function into a table, in which case you're pretty much just doing { unpack(table) } and ultimately getting the same table back. It's more likely that people want the table, or the ability to choose the starting point of the series than it is for them to want a series starting at index 1.
lieudusty #13
Posted 29 May 2013 - 11:44 PM
Sounds like a great project :D/>
ElvishJerricco #14
Posted 30 May 2013 - 12:12 AM
Sounds like a great project :D/>/>

Thanks! :)/> It's really aimed at the programmers of CC. That's why I don't call it an OS. Most operating systems for CC are designed to cater to the user with fancy UIs and some programs. Project NewLife is aimed at taking the idea of CraftOS and making it a much greater environment for a programmer.
ElvishJerricco #15
Posted 01 June 2013 - 04:10 AM
v1.0.1 released. No MegaNet yet (that's the name of the networking API I'm working on). But lots of littler tweaks which are cool anyways. I particularly like the file extension loaders system. Actually, if anyone wanted to spend the time to write a JavaScript to Lua compiler, that could be used as a loader so that you could just use the js source file as an API file.
ElvishJerricco #16
Posted 01 June 2013 - 05:52 PM
v1.0.2 released. The only difference is the new .coroutine file extension. These files will be loaded as courtines. Programs that use the multiple file system no longer use main.lua and its main function. Instead, they use main.coroutine and send the program arguments to the coroutine.
jesusthekiller #17
Posted 01 June 2013 - 07:20 PM
Stop. Spamming. Adverts, On. Other. Threads.

Period.




Also:
ElvishJerricco #18
Posted 02 June 2013 - 12:20 AM
Stop. Spamming. Adverts, On. Other. Threads.

Period.

I'm sorry. Really I didn't realize that's what I was doing. But next time don't be a dick about it. Send the guy a PM or something. You don't need to attempt to publicly humiliate them.

Edit: I'd like to add that this thread should just be about the project. Feedback, ideas, etc
ElvishJerricco #19
Posted 04 June 2013 - 02:32 AM
v1.0.3 will include a lasm assembler. Lasm has no standardized specification, so I will have an entire write-up about it. The purpose of lasm is to write lua bytecode manually. First of all, that's a fun chore. Second of all, it makes it easier to compile from some other language to lua bytecode, so I'll encourage people to write a compiler. I might even write an llvm backend for this.
Lyqyd #20
Posted 04 June 2013 - 02:55 AM
Stop. Spamming. Adverts, On. Other. Threads.

Period.




Also:

Don't backseat moderate. Use the report button.
jesusthekiller #21
Posted 04 June 2013 - 01:53 PM
I did…
ElvishJerricco #22
Posted 15 June 2013 - 11:17 PM
Updated to v1.1. Most notable feature is the new LASM compiler, for the first alternate programming language to be introduced to CC.
Stary2001 #23
Posted 18 June 2013 - 03:46 PM
Holy crap. wow. A Lua bytecode compiler in Lua. This is awesome.
Zudo #24
Posted 19 June 2013 - 12:42 PM
And before you ask, I am not in school. I am on my raspberry pi so no minecraft. My PC is virus scanning…

CC-EMU.
Too Laggy!
jesusthekiller #25
Posted 19 June 2013 - 01:09 PM
Holy crap. wow. A Lua bytecode compiler in Lua. This is awesome.


local function compile(file)
return string.dump(loadfile(file))
end
Will make bytecode too…
Stary2001 #26
Posted 19 June 2013 - 01:32 PM
it won't compile from a bytecode source file though, the power of this is being able to write bytecode directly rather than through the Lua compiler
-- helloworld.lasm
.stacksize 2
.const "Hello, World!" -- constant is at index 0
.const "print"
getglobal 0 1 -- load into register 0, the global with name from constant at index 1 ("print")
loadk 1 0 -- load into register 1, the constant at constant index 0 ("Hello, World!")
call 0 2 1 -- call the function at register 0, with 1 parameter, and keeping no returns.
is an example of lasm from the thread http://www.computercraft.info/forums2/index.php?/topic/13513-lasm-computercrafts-first-alternate-programming-language/
ElvishJerricco #27
Posted 19 June 2013 - 10:55 PM
it won't compile from a bytecode source file though, the power of this is being able to write bytecode directly rather than through the Lua compiler
-- helloworld.lasm
.stacksize 2
.const "Hello, World!" -- constant is at index 0
.const "print"
getglobal 0 1 -- load into register 0, the global with name from constant at index 1 ("print")
loadk 1 0 -- load into register 1, the constant at constant index 0 ("Hello, World!")
call 0 2 1 -- call the function at register 0, with 1 parameter, and keeping no returns.
is an example of lasm from the thread http://www.computerc...mming-language/

Hehe dunno if you noticed but I wrote both Project NewLife and LASM. That's why LASM is bundled with NewLife, and why the code for LASM is a little more nicely structured in NewLife.