blob: 5953f01e4d81bebf6a13be10af8b14a638e142de [file] [log] [blame]
--------------------------------------------------------------------------------
-- Copyright (c) 2012-2013 Sierra Wireless.
-- All rights reserved. This program and the accompanying materials
-- are made available under the terms of the Eclipse Public License v1.0
-- which accompanies this distribution, and is available at
-- http://www.eclipse.org/legal/epl-v10.html
--
-- Contributors:
-- Kevin KIN-FOO <kkinfoo@sierrawireless.com>
-- - initial API and implementation and initial documentation
--------------------------------------------------------------------------------
require 'metalua.loader'
local compiler = require 'metalua.compiler'
local mlc = compiler.new()
local javamodelfactory = require 'javamodelfactory'
-- Just redefining classic print, as there is a flush problem calling it from Java
local print = function(...) print(...) io.flush() end
local M = {}
---
-- Build Java Model from source code
--
-- @param #string source Code to parse
-- @return LuaSourceRoot, DLTK node, root of DLTK AST
function M.build(source, modulename)
-- create root object
local root = javamodelfactory.newsourceroot(#source)
-- manage shebang
if source then source = source:gsub("^(#.-\n)", function (s) return string.rep(' ',string.len(s)) end) end
-- check for errors
local f, err = loadstring(source,'source_to_check')
if not f then
local lineindex, errmessage = string.match(err,"%[string \"source_to_check\"%]:(%d+):(.*)")
errmessage = errmessage or err
lineindex = lineindex and tonumber(lineindex) or 1
javamodelfactory.setproblem(root,lineindex-1 , -1, -1, -1, errmessage)
-- -------------------------------------------------
-- EXPERIMENTAL CODE : we try to remove faulty code
-- -------------------------------------------------
local nbline = select(2, source:gsub('\n', '\n'))+1
if source and nbline > 1 then
-- define function that replace all character of a given line in space characters
local function cleanline (source, linetoclean,nbline)
local cleanedsource
local iscleaned = false
if linetoclean == nbline then
-- manage last line
cleanedsource = source:gsub('([^\n]-)$',function (lastline)
iscleaned = true
return string.rep(' ',string.len(lastline))
end)
elseif linetoclean == 1 then
-- manage first line
cleanedsource = source:gsub('^(.-)\n',function (firstline)
iscleaned = true
return string.rep(' ',string.len(firstline)).."\n"
end)
elseif linetoclean > 1 then
-- manage other case
cleanedsource = source:gsub('^('..string.rep(".-\n",linetoclean-1)..')(.-)\n',function (start,faultyline)
iscleaned = true
return start..string.rep(' ',string.len(faultyline)) .. "\n"
end)
end
return cleanedsource, iscleaned
end
local cleanedsource
local iscleaned = false
if lineindex == 1 then
-- FIRST LINE CASE : error is on line 1, just clean this line and check for errors
cleanedsource, iscleaned = cleanline(source,1,nbline)
f, _ = loadstring(cleanedsource,'source_to_check')
else
-- OTHER CASES: first, cleaning ...
-- if something is not closed we try to remove the line where it is opened.
local linestart = string.match(err,"%(to close .* at line (%d+)%)")
if linestart then
cleanedsource, iscleaned = cleanline(source,tonumber(linestart),nbline)
elseif lineindex > 1 then
-- in other case, we try to remove the "real" code line before the error
-- so, we start by finding the "real" line:
local realcodelineindex = nil
for i=lineindex-1,1,-1 do
-- we go from the line just before the error to the first line, searching a "real" code line.
-- (no empty line or single comment line, we do not manage multiline comment)
local codeline = source:match('^'..string.rep(".-\n",i-1)..'(.-)\n')
if codeline and not codeline:find('^%s*$') and not codeline:find('^%s*%-%-.*$') then
realcodelineindex = i
break
end
end
if realcodelineindex then
cleanedsource, iscleaned = cleanline(source,realcodelineindex,nbline)
end
end
-- after cleaning, recheck hoping there are no errors.
if iscleaned then
f, _ = loadstring(cleanedsource,'source_to_check')
-- if it fail, we try to remove the line in error
if not f then
cleanedsource = cleanline(source,lineindex,nbline)
f, _ = loadstring(cleanedsource,'source_to_check')
end
end
end
-- take cleaned source as source
if f then
source = cleanedsource
end
end
-- ------------------------------------------------
-- END OF EXPERIMENTAL CODE
-- -------------------------------------------------
end
if not f then return root end
-- if no errors, check AST
local ast = mlc:src_to_ast( source )
-- Create api model
local apimodelbuilder = require 'models.apimodelbuilder'
local _file, comment2apiobj = apimodelbuilder.createmoduleapi(ast,modulename)
-- create internal model
local internalmodelbuilder = require "models.internalmodelbuilder"
local _internalcontent = internalmodelbuilder.createinternalcontent(ast,_file,comment2apiobj,modulename)
-- Converting api model to java
local javaapimodelbuilder = require 'javaapimodelbuilder'
local jfile, handledexpr = javaapimodelbuilder._file(_file)
-- Converting internal model to java
local javainternalmodelbuilder = require 'javainternalmodelbuilder'
local jinternalcontent = javainternalmodelbuilder._internalcontent(_internalcontent,_file, handledexpr)
-- Append information from documentation
javamodelfactory.addcontent(root,jfile,jinternalcontent)
local handledcomments={}
-- TODO clean perf profiling
-- local e = os.clock()
-- print ('global time', type(e), type(s),(e*1000-s*1000))
return root
end
return M