Merge branch 'lua52'

Conflicts:
	plugins/org.eclipse.ldt.ui/OSGI-INF/l10n/bundle.properties
	plugins/org.eclipse.ldt.ui/src/org/eclipse/ldt/ui/wizards/LuaProjectCreator.java
	plugins/org.eclipse.ldt/META-INF/MANIFEST.MF
diff --git a/libraries/metalua/metalua/compiler/ast_to_src.mlua b/libraries/metalua/metalua/compiler/ast_to_src.mlua
index ca80a12..fd38516 100644
--- a/libraries/metalua/metalua/compiler/ast_to_src.mlua
+++ b/libraries/metalua/metalua/compiler/ast_to_src.mlua
@@ -389,6 +389,18 @@
     end
 end
 
+function M:Goto (node, name, annots)
+    print ("node",node, name); io.flush();
+    self:acc  "goto "
+    self:acc  (name)
+end
+
+function M:Label (node, name, annots)
+    self:acc  "::"
+    self:acc  (name)
+    self:acc  "::"
+end
+
 function M:Localrec (node, lhs, rhs)
    match node with
    | `Localrec{ { `Id{name} }, { `Function{ params, body } } }
diff --git a/libraries/metalua/metalua/compiler/parser/stat.lua b/libraries/metalua/metalua/compiler/parser/stat.lua
index 5d5e3a9..b262c1c 100644
--- a/libraries/metalua/metalua/compiler/parser/stat.lua
+++ b/libraries/metalua/metalua/compiler/parser/stat.lua
@@ -45,235 +45,237 @@
 
 
 return function(M)
-    local _M = gg.future(M)
+  local _M = gg.future(M)
 
-    M.block_terminators = { "else", "elseif", "end", "until", ")", "}", "]" }
+  M.block_terminators = { "else", "elseif", "end", "until", ")", "}", "]" }
 
-    -- FIXME: this must be handled from within GG!!!
-    -- FIXME: there's no :add method in the list anyway. Added by gg.list?!
-    function M.block_terminators :add(x)
-        if type (x) == "table" then for _, y in ipairs(x) do self :add (y) end
-        else table.insert (self, x) end
+  -- FIXME: this must be handled from within GG!!!
+  -- FIXME: there's no :add method in the list anyway. Added by gg.list?!
+  function M.block_terminators :add(x)
+    if type (x) == "table" then for _, y in ipairs(x) do self :add (y) end
+    else table.insert (self, x) end
+  end
+
+  ----------------------------------------------------------------------------
+  -- list of statements, possibly followed by semicolons
+  ----------------------------------------------------------------------------
+  M.block = gg.list {
+    name        = "statements block",
+    terminators = M.block_terminators,
+    primary     = function (lx)
+      -- FIXME use gg.optkeyword()
+      local x = M.stat (lx)
+      if lx:is_keyword (lx:peek(), ";") then lx:next() end
+      return x
+    end }
+
+  ----------------------------------------------------------------------------
+  -- Helper function for "return <expr_list>" parsing.
+  -- Called when parsing return statements.
+  -- The specific test for initial ";" is because it's not a block terminator,
+  -- so without it gg.list would choke on "return ;" statements.
+  -- We don't make a modified copy of block_terminators because this list
+  -- is sometimes modified at runtime, and the return parser would get out of
+  -- sync if it was relying on a copy.
+  ----------------------------------------------------------------------------
+  local return_expr_list_parser = gg.multisequence{
+    { ";" , builder = function() return { } end },
+    default = gg.list {
+      _M.expr, separators = ",", terminators = M.block_terminators } }
+
+
+  local for_vars_list = gg.list{
+    name        = "for variables list",
+    primary     = _M.id,
+    separators  = ",",
+    terminators = "in" }
+
+  ----------------------------------------------------------------------------
+  -- for header, between [for] and [do] (exclusive).
+  -- Return the `Forxxx{...} AST, without the body element (the last one).
+  ----------------------------------------------------------------------------
+  function M.for_header (lx)
+    local vars = M.id_list(lx)
+    if lx :is_keyword (lx:peek(), "=") then
+      if #vars ~= 1 then
+        gg.parse_error (lx, "numeric for only accepts one variable")
+      end
+      lx:next() -- skip "="
+      local exprs = M.expr_list (lx)
+      if #exprs < 2 or #exprs > 3 then
+        gg.parse_error (lx, "numeric for requires 2 or 3 boundaries")
+      end
+      return { tag="Fornum", vars[1], unpack (exprs) }
+    else
+      if not lx :is_keyword (lx :next(), "in") then
+        gg.parse_error (lx, '"=" or "in" expected in for loop')
+      end
+      local exprs = M.expr_list (lx)
+      return { tag="Forin", vars, exprs }
     end
+  end
 
-    ----------------------------------------------------------------------------
-    -- list of statements, possibly followed by semicolons
-    ----------------------------------------------------------------------------
-    M.block = gg.list {
-        name        = "statements block",
-        terminators = M.block_terminators,
-        primary     = function (lx)
-            -- FIXME use gg.optkeyword()
-            local x = M.stat (lx)
-            if lx:is_keyword (lx:peek(), ";") then lx:next() end
-            return x
-        end }
-
-    ----------------------------------------------------------------------------
-    -- Helper function for "return <expr_list>" parsing.
-    -- Called when parsing return statements.
-    -- The specific test for initial ";" is because it's not a block terminator,
-    -- so without it gg.list would choke on "return ;" statements.
-    -- We don't make a modified copy of block_terminators because this list
-    -- is sometimes modified at runtime, and the return parser would get out of
-    -- sync if it was relying on a copy.
-    ----------------------------------------------------------------------------
-    local return_expr_list_parser = gg.multisequence{
-        { ";" , builder = function() return { } end },
-        default = gg.list {
-            _M.expr, separators = ",", terminators = M.block_terminators } }
-
-
-    local for_vars_list = gg.list{
-        name        = "for variables list",
-        primary     = _M.id,
-        separators  = ",",
-        terminators = "in" }
-
-    ----------------------------------------------------------------------------
-    -- for header, between [for] and [do] (exclusive).
-    -- Return the `Forxxx{...} AST, without the body element (the last one).
-    ----------------------------------------------------------------------------
-    function M.for_header (lx)
-        local vars = M.id_list(lx)
-        if lx :is_keyword (lx:peek(), "=") then
-            if #vars ~= 1 then
-                gg.parse_error (lx, "numeric for only accepts one variable")
-            end
-            lx:next() -- skip "="
-            local exprs = M.expr_list (lx)
-            if #exprs < 2 or #exprs > 3 then
-                gg.parse_error (lx, "numeric for requires 2 or 3 boundaries")
-            end
-            return { tag="Fornum", vars[1], unpack (exprs) }
-        else
-            if not lx :is_keyword (lx :next(), "in") then
-                gg.parse_error (lx, '"=" or "in" expected in for loop')
-            end
-            local exprs = M.expr_list (lx)
-            return { tag="Forin", vars, exprs }
-        end
+  ----------------------------------------------------------------------------
+  -- Function def parser helper: id ( . id ) *
+  ----------------------------------------------------------------------------
+  local function fn_builder (list)
+    local acc = list[1]
+    local first = acc.lineinfo.first
+    for i = 2, #list do
+      local index = M.id2string(list[i])
+      local li = lexer.new_lineinfo(first, index.lineinfo.last)
+      acc = { tag="Index", acc, index, lineinfo=li }
     end
+    return acc
+  end
+  local func_name = gg.list{ _M.id, separators = ".", builder = fn_builder }
 
-    ----------------------------------------------------------------------------
-    -- Function def parser helper: id ( . id ) *
-    ----------------------------------------------------------------------------
-    local function fn_builder (list)
-        local acc = list[1]
-        local first = acc.lineinfo.first
-        for i = 2, #list do
-            local index = M.id2string(list[i])
-            local li = lexer.new_lineinfo(first, index.lineinfo.last)
-            acc = { tag="Index", acc, index, lineinfo=li }
-        end
-        return acc
+  ----------------------------------------------------------------------------
+  -- Function def parser helper: ( : id )?
+  ----------------------------------------------------------------------------
+  local method_name = gg.onkeyword{ name = "method invocation", ":", _M.id,
+    transformers = { function(x) return x and x.tag=='Id' and M.id2string(x) end } }
+
+  ----------------------------------------------------------------------------
+  -- Function def builder
+  ----------------------------------------------------------------------------
+  local function funcdef_builder(x)
+    local name, method, func = unpack(x)
+    if method then
+      name = { tag="Index", name, method,
+        lineinfo = {
+          first = name.lineinfo.first,
+          last  = method.lineinfo.last } }
+      table.insert (func[1], 1, {tag="Id", "self"})
     end
-    local func_name = gg.list{ _M.id, separators = ".", builder = fn_builder }
+    local r = { tag="Set", {name}, {func} }
+    r[1].lineinfo = name.lineinfo
+    r[2].lineinfo = func.lineinfo
+    return r
+  end
 
-    ----------------------------------------------------------------------------
-    -- Function def parser helper: ( : id )?
-    ----------------------------------------------------------------------------
-    local method_name = gg.onkeyword{ name = "method invocation", ":", _M.id,
-        transformers = { function(x) return x and x.tag=='Id' and M.id2string(x) end } }
 
-    ----------------------------------------------------------------------------
-    -- Function def builder
-    ----------------------------------------------------------------------------
-    local function funcdef_builder(x)
-        local name, method, func = unpack(x)
-        if method then
-            name = { tag="Index", name, method,
-                     lineinfo = {
-                         first = name.lineinfo.first,
-                         last  = method.lineinfo.last } }
-            table.insert (func[1], 1, {tag="Id", "self"})
-        end
-        local r = { tag="Set", {name}, {func} }
-        r[1].lineinfo = name.lineinfo
-        r[2].lineinfo = func.lineinfo
-        return r
+  ----------------------------------------------------------------------------
+  -- if statement builder
+  ----------------------------------------------------------------------------
+  local function if_builder (x)
+    local cond_block_pairs, else_block, r = x[1], x[2], {tag="If"}
+    local n_pairs = #cond_block_pairs
+    for i = 1, n_pairs do
+      local cond, block = unpack(cond_block_pairs[i])
+      r[2*i-1], r[2*i] = cond, block
     end
+    if else_block then table.insert(r, #r+1, else_block) end
+    return r
+  end
 
+  --------------------------------------------------------------------------------
+  -- produce a list of (expr,block) pairs
+  --------------------------------------------------------------------------------
+  local elseifs_parser = gg.list {
+    gg.sequence { _M.expr, "then", _M.block , name='elseif parser' },
+    separators  = "elseif",
+    terminators = { "else", "end" }
+  }
 
-    ----------------------------------------------------------------------------
-    -- if statement builder
-    ----------------------------------------------------------------------------
-    local function if_builder (x)
-        local cond_block_pairs, else_block, r = x[1], x[2], {tag="If"}
-        local n_pairs = #cond_block_pairs
-        for i = 1, n_pairs do
-            local cond, block = unpack(cond_block_pairs[i])
-            r[2*i-1], r[2*i] = cond, block
-        end
-        if else_block then table.insert(r, #r+1, else_block) end
-        return r
+  local annot_expr = gg.sequence {
+    _M.expr,
+    gg.onkeyword{ "#", gg.future(M, 'annot').tf },
+    builder = function(x)
+      local e, a = unpack(x)
+      if a then return { tag='Annot', e, a }
+      else return e end
+    end }
+
+  local annot_expr_list = gg.list {
+    primary = annot.opt(M, _M.expr, 'tf'), separators = ',' }
+
+  ------------------------------------------------------------------------
+  -- assignments and calls: statements that don't start with a keyword
+  ------------------------------------------------------------------------
+  local function assign_or_call_stat_parser (lx)
+    local e = annot_expr_list (lx)
+    local a = lx:is_keyword(lx:peek())
+    local op = a and M.assignments[a]
+    -- TODO: refactor annotations
+    if op then
+      --FIXME: check that [e] is a LHS
+      lx :next()
+      local annots
+      e, annots = annot.split(e)
+      local v = M.expr_list (lx)
+      if type(op)=="string" then return { tag=op, e, v, annots }
+      else return op (e, v) end
+    else
+      assert (#e > 0)
+      if #e > 1 then
+        gg.parse_error (lx,
+          "comma is not a valid statement separator; statement can be "..
+          "separated by semicolons, or not separated at all")
+      elseif e[1].tag ~= "Call" and e[1].tag ~= "Invoke" then
+        local typename
+        if e[1].tag == 'Id' then
+          typename = '("'..e[1][1]..'") is an identifier'
+        elseif e[1].tag == 'Op' then
+          typename = "is an arithmetic operation"
+        else typename = "is of type '"..(e[1].tag or "<list>").."'" end
+        gg.parse_error (lx,
+          "This expression %s; "..
+          "a statement was expected, and only function and method call "..
+          "expressions can be used as statements", typename);
+      end
+      return e[1]
     end
+  end
 
-    --------------------------------------------------------------------------------
-    -- produce a list of (expr,block) pairs
-    --------------------------------------------------------------------------------
-    local elseifs_parser = gg.list {
-        gg.sequence { _M.expr, "then", _M.block , name='elseif parser' },
-        separators  = "elseif",
-        terminators = { "else", "end" }
-    }
+  M.local_stat_parser = gg.multisequence{
+    -- local function <name> <func_val>
+    { "function", _M.id, _M.func_val, builder =
+      function(x)
+        local vars = { x[1], lineinfo = x[1].lineinfo }
+        local vals = { x[2], lineinfo = x[2].lineinfo }
+        return { tag="Localrec", vars, vals }
+      end },
+    -- local <id_list> ( = <expr_list> )?
+    default = gg.sequence{
+      gg.list{
+        primary = annot.opt(M, _M.id, 'tf'),
+        separators = ',' },
+      gg.onkeyword{ "=", _M.expr_list },
+      builder = function(x)
+        local annotated_left, right = unpack(x)
+        local left, annotations = annot.split(annotated_left)
+        return {tag="Local", left, right or { }, annotations }
+      end } }
 
-    local annot_expr = gg.sequence {
-        _M.expr,
-        gg.onkeyword{ "#", gg.future(M, 'annot').tf },
-        builder = function(x)
-            local e, a = unpack(x)
-            if a then return { tag='Annot', e, a }
-            else return e end
-        end }
+  ------------------------------------------------------------------------
+  -- statement
+  ------------------------------------------------------------------------
+  M.stat = gg.multisequence {
+    name = "statement",
+    { "do", _M.block, "end", builder =
+      function (x) return { tag="Do", unpack (x[1]) } end },
+    { "for", _M.for_header, "do", _M.block, "end", builder =
+      function (x) x[1][#x[1]+1] = x[2]; return x[1] end },
+    { "function", func_name, method_name, _M.func_val, builder=funcdef_builder },
+    { "while", _M.expr, "do", _M.block, "end", builder = "While" },
+    { "repeat", _M.block, "until", _M.expr, builder = "Repeat" },
+    { "goto", _M.id, builder = function(x) return {tag='Goto',x[1]} end },
+    { "::",_M.id,"::", builder = function(x) return {tag='Label',x[1]} end },
+    { "local", _M.local_stat_parser, builder = unpack },
+    { "return", return_expr_list_parser, builder =
+      function(x) x[1].tag='Return'; return x[1] end },
+    { "break", builder = function() return { tag="Break" } end },
+    { "-{", gg.future(M, 'meta').splice_content, "}", builder = unpack },
+    { "if", gg.nonempty(elseifs_parser), gg.onkeyword{ "else", M.block }, "end",
+      builder = if_builder },
+    default = assign_or_call_stat_parser }
 
-    local annot_expr_list = gg.list {
-        primary = annot.opt(M, _M.expr, 'tf'), separators = ',' }
+  M.assignments = {
+    ["="] = "Set"
+  }
 
-    ------------------------------------------------------------------------
-    -- assignments and calls: statements that don't start with a keyword
-    ------------------------------------------------------------------------
-    local function assign_or_call_stat_parser (lx)
-        local e = annot_expr_list (lx)
-        local a = lx:is_keyword(lx:peek())
-        local op = a and M.assignments[a]
-        -- TODO: refactor annotations
-        if op then
-            --FIXME: check that [e] is a LHS
-            lx :next()
-            local annots
-            e, annots = annot.split(e)
-            local v = M.expr_list (lx)
-            if type(op)=="string" then return { tag=op, e, v, annots }
-            else return op (e, v) end
-        else
-            assert (#e > 0)
-            if #e > 1 then
-                gg.parse_error (lx,
-                    "comma is not a valid statement separator; statement can be "..
-                    "separated by semicolons, or not separated at all")
-            elseif e[1].tag ~= "Call" and e[1].tag ~= "Invoke" then
-                local typename
-                if e[1].tag == 'Id' then
-                    typename = '("'..e[1][1]..'") is an identifier'
-                elseif e[1].tag == 'Op' then
-                    typename = "is an arithmetic operation"
-                else typename = "is of type '"..(e[1].tag or "<list>").."'" end
-                gg.parse_error (lx,
-                     "This expression %s; "..
-                     "a statement was expected, and only function and method call "..
-                     "expressions can be used as statements", typename);
-            end
-            return e[1]
-        end
-    end
+  function M.assignments:add(k, v) self[k] = v end
 
-    M.local_stat_parser = gg.multisequence{
-        -- local function <name> <func_val>
-        { "function", _M.id, _M.func_val, builder =
-          function(x)
-              local vars = { x[1], lineinfo = x[1].lineinfo }
-              local vals = { x[2], lineinfo = x[2].lineinfo }
-              return { tag="Localrec", vars, vals }
-          end },
-        -- local <id_list> ( = <expr_list> )?
-        default = gg.sequence{
-            gg.list{
-                primary = annot.opt(M, _M.id, 'tf'),
-                separators = ',' },
-            gg.onkeyword{ "=", _M.expr_list },
-            builder = function(x)
-                 local annotated_left, right = unpack(x)
-                 local left, annotations = annot.split(annotated_left)
-                 return {tag="Local", left, right or { }, annotations }
-             end } }
-
-    ------------------------------------------------------------------------
-    -- statement
-    ------------------------------------------------------------------------
-    M.stat = gg.multisequence {
-        name = "statement",
-        { "do", _M.block, "end", builder =
-          function (x) return { tag="Do", unpack (x[1]) } end },
-        { "for", _M.for_header, "do", _M.block, "end", builder =
-          function (x) x[1][#x[1]+1] = x[2]; return x[1] end },
-        { "function", func_name, method_name, _M.func_val, builder=funcdef_builder },
-        { "while", _M.expr, "do", _M.block, "end", builder = "While" },
-        { "repeat", _M.block, "until", _M.expr, builder = "Repeat" },
-        { "local", _M.local_stat_parser, builder = unpack },
-        { "return", return_expr_list_parser, builder =
-          function(x) x[1].tag='Return'; return x[1] end },
-        { "break", builder = function() return { tag="Break" } end },
-        { "-{", gg.future(M, 'meta').splice_content, "}", builder = unpack },
-        { "if", gg.nonempty(elseifs_parser), gg.onkeyword{ "else", M.block }, "end",
-          builder = if_builder },
-        default = assign_or_call_stat_parser }
-
-    M.assignments = {
-        ["="] = "Set"
-    }
-
-    function M.assignments:add(k, v) self[k] = v end
-
-    return M
-end
\ No newline at end of file
+  return M
+end
diff --git a/plugins/com.naef.jnlua-lua52/META-INF/MANIFEST.MF b/plugins/com.naef.jnlua-lua52/META-INF/MANIFEST.MF
index d3e1635..1fe6418 100644
--- a/plugins/com.naef.jnlua-lua52/META-INF/MANIFEST.MF
+++ b/plugins/com.naef.jnlua-lua52/META-INF/MANIFEST.MF
@@ -12,6 +12,7 @@
 Bundle-ActivationPolicy: lazy
 Export-Package: com.naef.jnlua,
  com.naef.jnlua.console,
+ com.naef.jnlua.eclipse,
  com.naef.jnlua.internal.osgi,
  com.naef.jnlua.script,
  com.naef.jnlua.util
diff --git a/plugins/com.naef.jnlua-lua52/src/com/naef/jnlua/eclipse/AbstractLuaModule.java b/plugins/com.naef.jnlua-lua52/src/com/naef/jnlua/eclipse/AbstractLuaModule.java
new file mode 100644
index 0000000..e4eb8a5
--- /dev/null
+++ b/plugins/com.naef.jnlua-lua52/src/com/naef/jnlua/eclipse/AbstractLuaModule.java
@@ -0,0 +1,146 @@
+/*******************************************************************************

+ * Copyright (c) 2011 Sierra Wireless and others.

+ * 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:

+ *     Sierra Wireless - initial API and implementation

+ *******************************************************************************/

+package com.naef.jnlua.eclipse;

+

+import java.io.File;

+import java.io.IOException;

+import java.net.URL;

+import java.util.ArrayList;

+import java.util.HashMap;

+import java.util.List;

+import java.util.Map;

+

+import org.eclipse.core.runtime.FileLocator;

+import org.eclipse.core.runtime.ILog;

+import org.eclipse.core.runtime.IStatus;

+import org.eclipse.core.runtime.Platform;

+import org.eclipse.core.runtime.Status;

+import org.eclipse.osgi.util.NLS;

+import org.osgi.framework.Bundle;

+

+import com.naef.jnlua.LuaState;

+import com.naef.jnlua.internal.osgi.Activator;

+

+/**

+ * Abstract class to manipulate Lua module

+ */

+public abstract class AbstractLuaModule {

+

+	private static final String LUA_PATTERN = "?.lua;"; //$NON-NLS-1$

+	private static final String LUAC_PATTERN = "?.luac;"; //$NON-NLS-1$

+

+	private Map<String, File> foldersCache = new HashMap<String, File>();

+

+	protected void definePaths(final LuaState luaState) {

+		// set lua path

+		final List<File> luaSourceFolders = getScriptFolders(getLuaSourcePaths());

+		final List<File> luacSourceFolders = getScriptFolders(getLuacSourcePaths());

+		setLuaPath(luaState, luaSourceFolders, luacSourceFolders);

+	}

+

+	/**

+	 * load the module with the name return by moduleName and store it in global var module name

+	 */

+	protected LuaState loadLuaModule() {

+		// get lua state

+		LuaState luaState = createLuaState();

+		definePaths(luaState);

+

+		// load module

+		luaState.getGlobal("require"); //$NON-NLS-1$

+		luaState.pushString(getModuleName());

+		luaState.call(1, 1);

+		luaState.setGlobal(getModuleName());

+

+		return luaState;

+	}

+

+	protected void pushLuaModule(LuaState luaState) {

+		luaState.getGlobal(getModuleName());

+	}

+

+	/**

+	 * return all the script folders

+	 */

+	protected List<File> getScriptFolders(List<String> folderRelativePaths) {

+		List<File> scriptFolders = new ArrayList<File>();

+		if (folderRelativePaths != null) {

+			for (String folderRelativePath : folderRelativePaths) {

+				File scriptFolder = getScriptFolder(folderRelativePath);

+				if (scriptFolder != null)

+					scriptFolders.add(scriptFolder);

+			}

+		}

+		return scriptFolders;

+	}

+

+	/**

+	 * return the folder in the bundle (pluginID) at the relative path

+	 */

+	protected File getScriptFolder(String relativepath) {

+		File folder = foldersCache.get(relativepath);

+		if (folder == null) {

+			try {

+				// extract file from bundle and get url

+				final URL folderUrl = FileLocator.toFileURL(Platform.getBundle(getPluginID()).getEntry(relativepath));

+				folder = new File(folderUrl.getFile());

+				foldersCache.put(relativepath, folder);

+			} catch (final IOException e) {

+				final String message = NLS.bind("Unable to get entry {0} in the plugin {1}.", relativepath, getPluginID());

+				log(IStatus.ERROR, message, e);

+			}

+		}

+		return folder;

+	}

+

+	/**

+	 * Add the given folders to the lua path

+	 */

+	public static void setLuaPath(LuaState luaState, List<File> luafolders, List<File> luacfolders) {

+		// Change path

+		final StringBuffer code = new StringBuffer("package.path=[["); //$NON-NLS-1$

+		for (File folder : luafolders) {

+			code.append(folder.getPath());

+			code.append(File.separatorChar);

+			code.append(LUA_PATTERN);

+		}

+		for (File folder : luacfolders) {

+			code.append(folder.getPath());

+			code.append(File.separatorChar);

+			code.append(LUAC_PATTERN);

+		}

+		code.append("]]..package.path"); //$NON-NLS-1$

+		luaState.load(code.toString(), "reloadingPath"); //$NON-NLS-1$

+		luaState.call(0, 0);

+	}

+

+	protected abstract List<String> getLuaSourcePaths();

+

+	protected abstract List<String> getLuacSourcePaths();

+

+	protected abstract LuaState createLuaState();

+

+	protected abstract String getPluginID();

+

+	protected abstract String getModuleName();

+

+	protected static void log(int severity, String message, Throwable throwable) {

+		// we use a 'special' way to log (without the org.eclipse.core.runtime.Plugin)

+		// because we want eclipse dependencie only for this package

+		Bundle bundle = Platform.getBundle(Activator.BUNDLEID);

+		if (bundle != null) {

+			ILog log = Platform.getLog(bundle);

+			if (log != null) {

+				log.log(new Status(severity, Activator.BUNDLEID, message, throwable));

+			}

+		}

+	}

+}

diff --git a/plugins/com.naef.jnlua-lua52/src/com/naef/jnlua/internal/osgi/Activator.java b/plugins/com.naef.jnlua-lua52/src/com/naef/jnlua/internal/osgi/Activator.java
index fe3f3f2..4043e65 100644
--- a/plugins/com.naef.jnlua-lua52/src/com/naef/jnlua/internal/osgi/Activator.java
+++ b/plugins/com.naef.jnlua-lua52/src/com/naef/jnlua/internal/osgi/Activator.java
@@ -5,6 +5,8 @@
 
 public class Activator implements BundleActivator {
 
+	public static final String BUNDLEID = "com.naef.jnlua";
+
 	private static BundleContext context;
 
 	static BundleContext getContext() {
@@ -13,11 +15,14 @@
 
 	/*
 	 * (non-Javadoc)
-	 * @see org.osgi.framework.BundleActivator#start(org.osgi.framework.BundleContext)
+	 * 
+	 * @see
+	 * org.osgi.framework.BundleActivator#start(org.osgi.framework.BundleContext
+	 * )
 	 */
 	public void start(BundleContext bundleContext) throws Exception {
 		Activator.context = bundleContext;
-		
+
 		// fixes a problem with binary interdependencies: a library cannot find
 		// its dependencies if they're inside the bundle
 		System.loadLibrary("lua52");
@@ -25,7 +30,9 @@
 
 	/*
 	 * (non-Javadoc)
-	 * @see org.osgi.framework.BundleActivator#stop(org.osgi.framework.BundleContext)
+	 * 
+	 * @see
+	 * org.osgi.framework.BundleActivator#stop(org.osgi.framework.BundleContext)
 	 */
 	public void stop(BundleContext bundleContext) throws Exception {
 		Activator.context = null;
diff --git a/plugins/org.eclipse.ldt.support.lua51/META-INF/MANIFEST.MF b/plugins/org.eclipse.ldt.support.lua51/META-INF/MANIFEST.MF
index 044186d..92adc8f 100644
--- a/plugins/org.eclipse.ldt.support.lua51/META-INF/MANIFEST.MF
+++ b/plugins/org.eclipse.ldt.support.lua51/META-INF/MANIFEST.MF
@@ -17,5 +17,6 @@
 Bundle-ActivationPolicy: lazy
 Bundle-RequiredExecutionEnvironment: JavaSE-1.6
 Export-Package: org.eclipse.ldt.support.lua51.internal;x-internal:=true,
- org.eclipse.ldt.support.lua51.internal.interpreter;x-internal:=true
+ org.eclipse.ldt.support.lua51.internal.interpreter;x-internal:=true,
+ org.eclipse.ldt.support.lua51.internal.validator;x-internal:=true
 
diff --git a/plugins/org.eclipse.ldt.support.lua51/build.properties b/plugins/org.eclipse.ldt.support.lua51/build.properties
index e6890ed..2073d00 100644
--- a/plugins/org.eclipse.ldt.support.lua51/build.properties
+++ b/plugins/org.eclipse.ldt.support.lua51/build.properties
@@ -16,7 +16,8 @@
                about.html,\

                resource/,\

                OSGI-INF/l10n/bundle.properties,\

-               OSGI-INF/

+               OSGI-INF/,\

+               script/

 # The java version of the source code

 javacSource=1.6

 # The java version of the byte code targeted

diff --git a/plugins/org.eclipse.ldt.support.lua51/plugin.xml b/plugins/org.eclipse.ldt.support.lua51/plugin.xml
index 6dd00f6..e5124d7 100644
--- a/plugins/org.eclipse.ldt.support.lua51/plugin.xml
+++ b/plugins/org.eclipse.ldt.support.lua51/plugin.xml
@@ -39,4 +39,12 @@
             name="Lua 5.1 on JNLua">

       </interpreterInstall>

    </extension>

+   <extension

+         point="org.eclipse.ldt.luaGrammar">

+      <grammar

+            keywords="and,break,do,else,elseif,end,false,for,function,if,in,local,nil,not,or,repeat,return,then,true,until,while"

+            name="lua-5.1"

+            validator="org.eclipse.ldt.support.lua51.internal.validator.Lua51SourceValidator">

+      </grammar>

+   </extension>
 </plugin>

diff --git a/plugins/org.eclipse.ldt.support.lua51/script/internal/lua51validator.lua b/plugins/org.eclipse.ldt.support.lua51/script/internal/lua51validator.lua
new file mode 100644
index 0000000..6b09490
--- /dev/null
+++ b/plugins/org.eclipse.ldt.support.lua51/script/internal/lua51validator.lua
@@ -0,0 +1,106 @@
+local M = {}
+
+function M.valid (source, root)
+  -- 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')
+  local errmessage, lineindex
+
+  if not f then
+    lineindex, errmessage = string.match(err,"%[string \"source_to_check\"%]:(%d+):(.*)")
+    errmessage = errmessage or err
+    lineindex = lineindex and tonumber(lineindex) or 1
+
+    -- -------------------------------------------------
+    -- 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
+
+  -- return only valid source code
+  if f then
+    return source, errmessage, lineindex
+  else
+    return nil, errmessage,lineindex
+  end
+end
+
+return M
diff --git a/plugins/org.eclipse.ldt.support.lua51/src/org/eclipse/ldt/support/lua51/internal/validator/Lua51SourceValidator.java b/plugins/org.eclipse.ldt.support.lua51/src/org/eclipse/ldt/support/lua51/internal/validator/Lua51SourceValidator.java
new file mode 100644
index 0000000..a6afa55
--- /dev/null
+++ b/plugins/org.eclipse.ldt.support.lua51/src/org/eclipse/ldt/support/lua51/internal/validator/Lua51SourceValidator.java
@@ -0,0 +1,122 @@
+package org.eclipse.ldt.support.lua51.internal.validator;
+
+import java.util.ArrayList;
+import java.util.List;
+
+import org.eclipse.ldt.core.grammar.ILuaSourceValidator;
+import org.eclipse.ldt.support.lua51.internal.Activator;
+
+import com.naef.jnlua.LuaRuntimeException;
+import com.naef.jnlua.LuaState;
+import com.naef.jnlua.eclipse.AbstractLuaModule;
+
+public class Lua51SourceValidator extends AbstractLuaModule implements ILuaSourceValidator {
+
+	private static final String VALIDATOR_PATH = "script/internal"; //$NON-NLS-1$
+	private static final String MODULE_NAME = "lua51validator"; //$NON-NLS-1$
+	private static final String VALIDATION_FUNCTION = "valid"; //$NON-NLS-1$
+
+	private LuaState lua;
+
+	private String cleanedSource;
+	private String errorMessage;
+	private int lineIndex;
+
+	public Lua51SourceValidator() {
+	}
+
+	@Override
+	public boolean valid(String source) {
+		// Load function
+		if (lua == null)
+			lua = loadLuaModule();
+
+		pushLuaModule(lua);
+		lua.getField(-1, VALIDATION_FUNCTION);
+		lua.pushString(source);
+		try {
+			lua.call(1, 3);
+		} catch (final LuaRuntimeException e) {
+			Activator.logWarning("validation 5.1 failed", e); //$NON-NLS-1$
+			cleanedSource = null;
+			errorMessage = "Unexpected error ..."; //$NON-NLS-1$
+			lineIndex = 0;
+			return false;
+		}
+
+		cleanedSource = lua.toString(-3);
+		errorMessage = lua.toString(-2);
+		lineIndex = Math.max(lua.toInteger(-1) - 1, 0);
+
+		return errorMessage == null;
+	}
+
+	/**
+	 * @see com.naef.jnlua.eclipse.AbstractLuaModule#getLuaSourcePaths()
+	 */
+	@Override
+	protected List<String> getLuaSourcePaths() {
+		ArrayList<String> sourcepaths = new ArrayList<String>();
+		sourcepaths.add(VALIDATOR_PATH);
+		return sourcepaths;
+	}
+
+	/**
+	 * @see com.naef.jnlua.eclipse.AbstractLuaModule#getLuacSourcePaths()
+	 */
+	@Override
+	protected List<String> getLuacSourcePaths() {
+		return null;
+	}
+
+	/**
+	 * @see com.naef.jnlua.eclipse.AbstractLuaModule#createLuaState()
+	 */
+	@Override
+	protected LuaState createLuaState() {
+		LuaState l = new LuaState();
+		l.openLibs();
+		return l;
+	}
+
+	/**
+	 * @see com.naef.jnlua.eclipse.AbstractLuaModule#getPluginID()
+	 */
+	@Override
+	protected String getPluginID() {
+		return Activator.PLUGIN_ID;
+	}
+
+	/**
+	 * @see com.naef.jnlua.eclipse.AbstractLuaModule#getModuleName()
+	 */
+	@Override
+	protected String getModuleName() {
+		return MODULE_NAME;
+	}
+
+	/**
+	 * @see org.eclipse.ldt.core.grammar.ILuaSourceValidator#getCleanedSource()
+	 */
+	@Override
+	public String getCleanedSource() {
+		return cleanedSource;
+	}
+
+	/**
+	 * @see org.eclipse.ldt.core.grammar.ILuaSourceValidator#getErrorMessage()
+	 */
+	@Override
+	public String getErrorMessage() {
+		return errorMessage;
+	}
+
+	/**
+	 * @see org.eclipse.ldt.core.grammar.ILuaSourceValidator#getLineIndex()
+	 */
+	@Override
+	public int getLineIndex() {
+		return lineIndex;
+	}
+
+}
diff --git a/plugins/org.eclipse.ldt.support.lua52/META-INF/MANIFEST.MF b/plugins/org.eclipse.ldt.support.lua52/META-INF/MANIFEST.MF
index 35f6d3e..2501e74 100644
--- a/plugins/org.eclipse.ldt.support.lua52/META-INF/MANIFEST.MF
+++ b/plugins/org.eclipse.ldt.support.lua52/META-INF/MANIFEST.MF
@@ -17,5 +17,6 @@
 Bundle-ActivationPolicy: lazy
 Bundle-RequiredExecutionEnvironment: JavaSE-1.6
 Export-Package: org.eclipse.ldt.support.lua52.internal;x-internal:=true,
- org.eclipse.ldt.support.lua52.internal.interpreter;x-internal:=true
+ org.eclipse.ldt.support.lua52.internal.interpreter;x-internal:=true,
+ org.eclipse.ldt.support.lua52.internal.validator;x-internal:=true
 
diff --git a/plugins/org.eclipse.ldt.support.lua52/build.properties b/plugins/org.eclipse.ldt.support.lua52/build.properties
index ffaaac7..b38170b 100644
--- a/plugins/org.eclipse.ldt.support.lua52/build.properties
+++ b/plugins/org.eclipse.ldt.support.lua52/build.properties
@@ -16,7 +16,8 @@
                about.html,\

                resource/,\

                OSGI-INF/l10n/bundle.properties,\

-               OSGI-INF/

+               OSGI-INF/,\

+               script/

 # The java version of the source code

 javacSource=1.6

 # The java version of the byte code targeted

diff --git a/plugins/org.eclipse.ldt.support.lua52/plugin.xml b/plugins/org.eclipse.ldt.support.lua52/plugin.xml
index 35464b1..6f0d6ad 100644
--- a/plugins/org.eclipse.ldt.support.lua52/plugin.xml
+++ b/plugins/org.eclipse.ldt.support.lua52/plugin.xml
@@ -39,4 +39,12 @@
             name="Lua 5.2 on JNLua">

       </interpreterInstall>

    </extension>

+   <extension

+         point="org.eclipse.ldt.luaGrammar">

+      <grammar

+            keywords="goto,::,and,break,do,else,elseif,end,false,for,function,if,in,local,nil,not,or,repeat,return,then,true,until,while"

+            name="lua-5.2"

+            validator="org.eclipse.ldt.support.lua52.internal.validator.Lua52SourceValidator">

+      </grammar>

+   </extension>

 </plugin>

diff --git a/plugins/org.eclipse.ldt.support.lua52/script/internal/lua52validator.lua b/plugins/org.eclipse.ldt.support.lua52/script/internal/lua52validator.lua
new file mode 100644
index 0000000..6b09490
--- /dev/null
+++ b/plugins/org.eclipse.ldt.support.lua52/script/internal/lua52validator.lua
@@ -0,0 +1,106 @@
+local M = {}
+
+function M.valid (source, root)
+  -- 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')
+  local errmessage, lineindex
+
+  if not f then
+    lineindex, errmessage = string.match(err,"%[string \"source_to_check\"%]:(%d+):(.*)")
+    errmessage = errmessage or err
+    lineindex = lineindex and tonumber(lineindex) or 1
+
+    -- -------------------------------------------------
+    -- 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
+
+  -- return only valid source code
+  if f then
+    return source, errmessage, lineindex
+  else
+    return nil, errmessage,lineindex
+  end
+end
+
+return M
diff --git a/plugins/org.eclipse.ldt.support.lua52/src/org/eclipse/ldt/support/lua52/internal/Activator.java b/plugins/org.eclipse.ldt.support.lua52/src/org/eclipse/ldt/support/lua52/internal/Activator.java
index 7f6da5d..afa85a0 100644
--- a/plugins/org.eclipse.ldt.support.lua52/src/org/eclipse/ldt/support/lua52/internal/Activator.java
+++ b/plugins/org.eclipse.ldt.support.lua52/src/org/eclipse/ldt/support/lua52/internal/Activator.java
@@ -18,7 +18,7 @@
 public class Activator extends Plugin {

 

 	/** The plug-in ID */

-	public static final String PLUGIN_ID = "org.eclipse.ldt.support.lua51"; //$NON-NLS-1$

+	public static final String PLUGIN_ID = "org.eclipse.ldt.support.lua52"; //$NON-NLS-1$

 

 	/** The shared instance */

 	private static Activator plugin;

diff --git a/plugins/org.eclipse.ldt.support.lua52/src/org/eclipse/ldt/support/lua52/internal/validator/Lua52SourceValidator.java b/plugins/org.eclipse.ldt.support.lua52/src/org/eclipse/ldt/support/lua52/internal/validator/Lua52SourceValidator.java
new file mode 100644
index 0000000..4c220c9
--- /dev/null
+++ b/plugins/org.eclipse.ldt.support.lua52/src/org/eclipse/ldt/support/lua52/internal/validator/Lua52SourceValidator.java
@@ -0,0 +1,122 @@
+package org.eclipse.ldt.support.lua52.internal.validator;
+
+import java.util.ArrayList;
+import java.util.List;
+
+import org.eclipse.ldt.core.grammar.ILuaSourceValidator;
+import org.eclipse.ldt.support.lua52.internal.Activator;
+
+import com.naef.jnlua.LuaRuntimeException;
+import com.naef.jnlua.LuaState;
+import com.naef.jnlua.eclipse.AbstractLuaModule;
+
+public class Lua52SourceValidator extends AbstractLuaModule implements ILuaSourceValidator {
+
+	private static final String VALIDATOR_PATH = "script/internal"; //$NON-NLS-1$
+	private static final String MODULE_NAME = "lua52validator"; //$NON-NLS-1$
+	private static final String VALIDATION_FUNCTION = "valid"; //$NON-NLS-1$
+
+	private LuaState lua;
+
+	private String cleanedSource;
+	private String errorMessage;
+	private int lineIndex;
+
+	public Lua52SourceValidator() {
+	}
+
+	@Override
+	public boolean valid(String source) {
+		// Load function
+		if (lua == null)
+			lua = loadLuaModule();
+
+		pushLuaModule(lua);
+		lua.getField(-1, VALIDATION_FUNCTION);
+		lua.pushString(source);
+		try {
+			lua.call(1, 3);
+		} catch (final LuaRuntimeException e) {
+			Activator.logWarning("validation 5.2 failed", e); //$NON-NLS-1$
+			cleanedSource = null;
+			errorMessage = "Unexpected error ..."; //$NON-NLS-1$
+			lineIndex = 0;
+			return false;
+		}
+
+		cleanedSource = lua.toString(-3);
+		errorMessage = lua.toString(-2);
+		lineIndex = Math.max(lua.toInteger(-1) - 1, 0);
+
+		return errorMessage == null;
+	}
+
+	/**
+	 * @see com.naef.jnlua.eclipse.AbstractLuaModule#getLuaSourcePaths()
+	 */
+	@Override
+	protected List<String> getLuaSourcePaths() {
+		ArrayList<String> sourcepaths = new ArrayList<String>();
+		sourcepaths.add(VALIDATOR_PATH);
+		return sourcepaths;
+	}
+
+	/**
+	 * @see com.naef.jnlua.eclipse.AbstractLuaModule#getLuacSourcePaths()
+	 */
+	@Override
+	protected List<String> getLuacSourcePaths() {
+		return null;
+	}
+
+	/**
+	 * @see com.naef.jnlua.eclipse.AbstractLuaModule#createLuaState()
+	 */
+	@Override
+	protected LuaState createLuaState() {
+		LuaState l = new LuaState();
+		l.openLibs();
+		return l;
+	}
+
+	/**
+	 * @see com.naef.jnlua.eclipse.AbstractLuaModule#getPluginID()
+	 */
+	@Override
+	protected String getPluginID() {
+		return Activator.PLUGIN_ID;
+	}
+
+	/**
+	 * @see com.naef.jnlua.eclipse.AbstractLuaModule#getModuleName()
+	 */
+	@Override
+	protected String getModuleName() {
+		return MODULE_NAME;
+	}
+
+	/**
+	 * @see org.eclipse.ldt.core.grammar.ILuaSourceValidator#getCleanedSource()
+	 */
+	@Override
+	public String getCleanedSource() {
+		return cleanedSource;
+	}
+
+	/**
+	 * @see org.eclipse.ldt.core.grammar.ILuaSourceValidator#getErrorMessage()
+	 */
+	@Override
+	public String getErrorMessage() {
+		return errorMessage;
+	}
+
+	/**
+	 * @see org.eclipse.ldt.core.grammar.ILuaSourceValidator#getLineIndex()
+	 */
+	@Override
+	public int getLineIndex() {
+		return lineIndex;
+	}
+
+}
diff --git a/plugins/org.eclipse.ldt.ui/OSGI-INF/l10n/bundle.properties b/plugins/org.eclipse.ldt.ui/OSGI-INF/l10n/bundle.properties
index 41bca8f..3258fcd 100644
--- a/plugins/org.eclipse.ldt.ui/OSGI-INF/l10n/bundle.properties
+++ b/plugins/org.eclipse.ldt.ui/OSGI-INF/l10n/bundle.properties
@@ -50,4 +50,6 @@
 decorator.label.doclua = Decorator for doclua files.
 rename.command.label = Rename a variable
 
-command.converttoluaproject.name = Convert to Lua project ...
\ No newline at end of file
+command.converttoluaproject.name = Convert to Lua project ...
+preference.page.name.grammars = Grammars
+property.page.name.grammar = Grammar
diff --git a/plugins/org.eclipse.ldt.ui/icons/obj16/grammar.png b/plugins/org.eclipse.ldt.ui/icons/obj16/grammar.png
new file mode 100644
index 0000000..c3d1e9b
--- /dev/null
+++ b/plugins/org.eclipse.ldt.ui/icons/obj16/grammar.png
Binary files differ
diff --git a/plugins/org.eclipse.ldt.ui/plugin.xml b/plugins/org.eclipse.ldt.ui/plugin.xml
index 7c41c20..f829973 100644
--- a/plugins/org.eclipse.ldt.ui/plugin.xml
+++ b/plugins/org.eclipse.ldt.ui/plugin.xml
@@ -35,6 +35,12 @@
             class="org.eclipse.ldt.ui.internal.preferences.LuaTodoTaskPreferencePage"
             id="org.eclipse.ldt.ui.todo"
             name="%preference.page.name.todotasks"/>
+      <page
+            category="org.eclipse.ldt.ui.globalpreferencepage"
+            class="org.eclipse.ldt.ui.internal.preferences.LuaGrammarPreferencePage"
+            id="org.eclipse.ldt.ui.grammarpreferencepage"
+            name="%preference.page.name.grammars">
+      </page>
    </extension>
       <extension
          point="org.eclipse.ui.ide.projectNatureImages">
@@ -92,6 +98,21 @@
         </adapt>
       </enabledWhen>
     </page>
+    <page
+          category="org.eclipse.ldt.ui.lua.page"
+          class="org.eclipse.ldt.ui.internal.properties.GrammarPropertyPage"
+          id="org.eclipse.ldt.ui.lua.grammar"
+          name="%property.page.name.grammar">
+       <enabledWhen>
+          <adapt
+                type="org.eclipse.core.resources.IProject">
+             <test
+                   property="org.eclipse.core.resources.projectNature"
+                   value="org.eclipse.ldt.nature">
+             </test>
+          </adapt>
+       </enabledWhen>
+    </page>
  </extension>
      <extension
            point="org.eclipse.dltk.ui.buildpathContainerPage">
diff --git a/plugins/org.eclipse.ldt.ui/src/org/eclipse/ldt/ui/internal/Activator.java b/plugins/org.eclipse.ldt.ui/src/org/eclipse/ldt/ui/internal/Activator.java
index e6e15e0..b85fd3e 100644
--- a/plugins/org.eclipse.ldt.ui/src/org/eclipse/ldt/ui/internal/Activator.java
+++ b/plugins/org.eclipse.ldt.ui/src/org/eclipse/ldt/ui/internal/Activator.java
@@ -103,6 +103,8 @@
 
 		reg.put(ImageConstants.DOCLUA_OVERLAY, AbstractUIPlugin.imageDescriptorFromPlugin(PLUGIN_ID, ImageConstants.DOCLUA_OVERLAY));
 		reg.put(ImageConstants.DOCLUA_FILE_WIZARD_BAN, AbstractUIPlugin.imageDescriptorFromPlugin(PLUGIN_ID, ImageConstants.DOCLUA_FILE_WIZARD_BAN));
+
+		reg.put(ImageConstants.GRAMMAR_OBJ16, AbstractUIPlugin.imageDescriptorFromPlugin(PLUGIN_ID, ImageConstants.GRAMMAR_OBJ16));
 	}
 
 	/**
diff --git a/plugins/org.eclipse.ldt.ui/src/org/eclipse/ldt/ui/internal/ImageConstants.java b/plugins/org.eclipse.ldt.ui/src/org/eclipse/ldt/ui/internal/ImageConstants.java
index 9b70e3a..b8c7839 100644
--- a/plugins/org.eclipse.ldt.ui/src/org/eclipse/ldt/ui/internal/ImageConstants.java
+++ b/plugins/org.eclipse.ldt.ui/src/org/eclipse/ldt/ui/internal/ImageConstants.java
@@ -34,4 +34,6 @@
 

 	String DOCLUA_OVERLAY = "icons/ovr16/doclua.png"; //$NON-NLS-1$

 	String DOCLUA_FILE_WIZARD_BAN = "icons/wizban/doclua_newfile_wiz.png"; //$NON-NLS-1$

+

+	String GRAMMAR_OBJ16 = "icons/obj16/grammar.png"; //$NON-NLS-1$

 }

diff --git a/plugins/org.eclipse.ldt.ui/src/org/eclipse/ldt/ui/internal/editor/text/LuaCodeScanner.java b/plugins/org.eclipse.ldt.ui/src/org/eclipse/ldt/ui/internal/editor/text/LuaCodeScanner.java
index f8daa55..8e71f22 100644
--- a/plugins/org.eclipse.ldt.ui/src/org/eclipse/ldt/ui/internal/editor/text/LuaCodeScanner.java
+++ b/plugins/org.eclipse.ldt.ui/src/org/eclipse/ldt/ui/internal/editor/text/LuaCodeScanner.java
@@ -14,6 +14,7 @@
 import java.util.ArrayList;
 import java.util.List;
 
+import org.eclipse.core.runtime.CoreException;
 import org.eclipse.dltk.ui.text.AbstractScriptScanner;
 import org.eclipse.dltk.ui.text.IColorManager;
 import org.eclipse.jface.preference.IPreferenceStore;
@@ -26,13 +27,14 @@
 import org.eclipse.jface.text.rules.Token;
 import org.eclipse.jface.text.rules.WhitespaceRule;
 import org.eclipse.jface.text.rules.WordRule;
+import org.eclipse.jface.util.PropertyChangeEvent;
+import org.eclipse.ldt.core.grammar.IGrammar;
+import org.eclipse.ldt.core.internal.PreferenceInitializer;
+import org.eclipse.ldt.core.internal.grammar.LuaGrammarManager;
+import org.eclipse.ldt.ui.internal.Activator;
 
 public class LuaCodeScanner extends AbstractScriptScanner {
 
-	@SuppressWarnings("nls")
-	private static String[] fgKeywords = { "and", "break", "do", "else", "elseif", "end", "false", "for", "function", "if", "in", "local", "nil",
-			"not", "or", "repeat", "return", "then", "true", "until", "while" };
-
 	private static String[] fgTokenProperties = new String[] { ILuaColorConstants.LUA_NUMBER, ILuaColorConstants.LUA_DEFAULT,
 			ILuaColorConstants.LUA_KEYWORD };
 
@@ -54,10 +56,28 @@
 		// Add generic whitespace rule.
 		rules.add(new WhitespaceRule(new LuaWhitespaceDetector()));
 
-		// Add word rule for keywords.
+		// Get grammarName
+		String grammarName = getPreferenceStore().getString(PreferenceInitializer.GRAMMAR_DEFAULT_ID);
+		if (grammarName == null || grammarName.isEmpty())
+			grammarName = PreferenceInitializer.GRAMMAR_DEFAULT_ID_VALUE;
+
+		// Get grammar
+		IGrammar grammar = null;
+		try {
+			grammar = LuaGrammarManager.getAvailableGrammar(grammarName);
+			if (grammar == null) {
+				Activator.logWarning(String.format("Unable to find grammar for %s", grammarName)); //$NON-NLS-1$
+			}
+		} catch (CoreException e) {
+			Activator.logWarning(String.format("Unable to find grammar for %s", grammarName), e); //$NON-NLS-1$
+		}
+
+		// Add word rule for each keywords of grammar
 		final WordRule wordRule = new WordRule(new LuaWordDetector(), other);
-		for (int i = 0; i < fgKeywords.length; i++) {
-			wordRule.addWord(fgKeywords[i], keyword);
+		if (grammar != null) {
+			for (String word : grammar.getKeywords()) {
+				wordRule.addWord(word, keyword);
+			}
 		}
 		rules.add(wordRule);
 
@@ -71,6 +91,26 @@
 	}
 
 	/**
+	 * @see org.eclipse.dltk.ui.text.AbstractScriptScanner#affectsBehavior(org.eclipse.jface.util.PropertyChangeEvent)
+	 */
+	@Override
+	public boolean affectsBehavior(PropertyChangeEvent event) {
+		return PreferenceInitializer.GRAMMAR_DEFAULT_ID.equals(event.getProperty()) || super.affectsBehavior(event);
+	}
+
+	/**
+	 * @see org.eclipse.dltk.ui.text.AbstractScriptScanner#adaptToPreferenceChange(org.eclipse.jface.util.PropertyChangeEvent)
+	 */
+	@Override
+	public void adaptToPreferenceChange(PropertyChangeEvent event) {
+		if (PreferenceInitializer.GRAMMAR_DEFAULT_ID.equals(event.getProperty())) {
+			initialize();
+		} else {
+			super.adaptToPreferenceChange(event);
+		}
+	}
+
+	/**
 	 * Indicates if argument is a white space
 	 * 
 	 * @param char Tested character
diff --git a/plugins/org.eclipse.ldt.ui/src/org/eclipse/ldt/ui/internal/grammar/GrammarContentProvider.java b/plugins/org.eclipse.ldt.ui/src/org/eclipse/ldt/ui/internal/grammar/GrammarContentProvider.java
new file mode 100644
index 0000000..b5be807
--- /dev/null
+++ b/plugins/org.eclipse.ldt.ui/src/org/eclipse/ldt/ui/internal/grammar/GrammarContentProvider.java
@@ -0,0 +1,53 @@
+/*******************************************************************************
+ * Copyright (c) 2015 Sierra Wireless and others.
+ * 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:
+ *     Sierra Wireless - initial API and implementation
+ *******************************************************************************/
+package org.eclipse.ldt.ui.internal.grammar;
+
+import java.util.Arrays;
+import java.util.List;
+
+import org.eclipse.jface.viewers.ITreeContentProvider;
+import org.eclipse.jface.viewers.Viewer;
+
+public class GrammarContentProvider implements ITreeContentProvider {
+
+	@Override
+	public void dispose() {
+	}
+
+	@Override
+	public void inputChanged(Viewer viewer, Object oldInput, Object newInput) {
+	}
+
+	@Override
+	public Object[] getElements(Object inputElement) {
+		if (inputElement instanceof List<?>) {
+			Object[] array = ((List<?>) inputElement).toArray();
+			Arrays.sort(array);
+			return array;
+		}
+		return null;
+	}
+
+	@Override
+	public Object[] getChildren(Object parentElement) {
+		return null;
+	}
+
+	@Override
+	public Object getParent(Object element) {
+		return null;
+	}
+
+	@Override
+	public boolean hasChildren(Object element) {
+		return false;
+	}
+}
diff --git a/plugins/org.eclipse.ldt.ui/src/org/eclipse/ldt/ui/internal/grammar/GrammarLabelProvider.java b/plugins/org.eclipse.ldt.ui/src/org/eclipse/ldt/ui/internal/grammar/GrammarLabelProvider.java
new file mode 100644
index 0000000..0614055
--- /dev/null
+++ b/plugins/org.eclipse.ldt.ui/src/org/eclipse/ldt/ui/internal/grammar/GrammarLabelProvider.java
@@ -0,0 +1,50 @@
+/*******************************************************************************
+ * Copyright (c) 2015 Sierra Wireless and others.
+ * 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:
+ *     Sierra Wireless - initial API and implementation
+ *******************************************************************************/
+package org.eclipse.ldt.ui.internal.grammar;
+
+import org.eclipse.jface.viewers.ILabelProvider;
+import org.eclipse.jface.viewers.ILabelProviderListener;
+import org.eclipse.ldt.ui.internal.Activator;
+import org.eclipse.ldt.ui.internal.ImageConstants;
+import org.eclipse.swt.graphics.Image;
+
+public class GrammarLabelProvider implements ILabelProvider {
+
+	@Override
+	public void addListener(ILabelProviderListener listener) {
+	}
+
+	@Override
+	public void dispose() {
+	}
+
+	@Override
+	public boolean isLabelProperty(Object element, String property) {
+		return false;
+	}
+
+	@Override
+	public void removeListener(ILabelProviderListener listener) {
+	}
+
+	@Override
+	public Image getImage(Object element) {
+		return Activator.getDefault().getImageRegistry().get(ImageConstants.GRAMMAR_OBJ16);
+	}
+
+	@Override
+	public String getText(Object element) {
+		if (element != null) {
+			return element.toString();
+		}
+		return null;
+	}
+}
\ No newline at end of file
diff --git a/plugins/org.eclipse.ldt.ui/src/org/eclipse/ldt/ui/internal/preferences/LuaGrammarPreferencePage.java b/plugins/org.eclipse.ldt.ui/src/org/eclipse/ldt/ui/internal/preferences/LuaGrammarPreferencePage.java
new file mode 100644
index 0000000..221c55d
--- /dev/null
+++ b/plugins/org.eclipse.ldt.ui/src/org/eclipse/ldt/ui/internal/preferences/LuaGrammarPreferencePage.java
@@ -0,0 +1,110 @@
+/*******************************************************************************
+ * Copyright (c) 2009, 2012 Sierra Wireless and others.
+ * 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:
+ *     Sierra Wireless - initial API and implementation
+ ******************************************************************************/
+package org.eclipse.ldt.ui.internal.preferences;
+
+import java.util.List;
+
+import org.eclipse.core.runtime.preferences.InstanceScope;
+import org.eclipse.jface.layout.GridDataFactory;
+import org.eclipse.jface.layout.GridLayoutFactory;
+import org.eclipse.jface.preference.PreferencePage;
+import org.eclipse.jface.viewers.CheckStateChangedEvent;
+import org.eclipse.jface.viewers.CheckboxTreeViewer;
+import org.eclipse.jface.viewers.ICheckStateListener;
+import org.eclipse.ldt.core.internal.LuaLanguageToolkit;
+import org.eclipse.ldt.core.internal.PreferenceInitializer;
+import org.eclipse.ldt.core.internal.grammar.LuaGrammarManager;
+import org.eclipse.ldt.ui.internal.grammar.GrammarContentProvider;
+import org.eclipse.ldt.ui.internal.grammar.GrammarLabelProvider;
+import org.eclipse.swt.SWT;
+import org.eclipse.swt.widgets.Composite;
+import org.eclipse.swt.widgets.Control;
+import org.eclipse.ui.IWorkbench;
+import org.eclipse.ui.IWorkbenchPreferencePage;
+import org.eclipse.ui.preferences.ScopedPreferenceStore;
+
+public class LuaGrammarPreferencePage extends PreferencePage implements IWorkbenchPreferencePage {
+
+	private CheckboxTreeViewer eeTreeViewer;
+
+	protected String getHelpId() {
+		return null;
+	}
+
+	@Override
+	public void init(IWorkbench workbench) {
+		setDescription(Messages.LuaGrammarPreferencePage_page_description);
+		noDefaultAndApplyButton();
+		setPreferenceStore(new ScopedPreferenceStore(InstanceScope.INSTANCE, LuaLanguageToolkit.getDefault().getPreferenceQualifier()));
+	}
+
+	/**
+	 * @see org.eclipse.jface.preference.PreferencePage#createContents(org.eclipse.swt.widgets.Composite)
+	 */
+	@Override
+	protected Control createContents(Composite parent) {
+		// ----------------
+		// CREATE CONTROL
+		// create container composite
+		Composite containerComposite = new Composite(parent, SWT.NONE);
+		GridLayoutFactory.swtDefaults().margins(0, 0).numColumns(2).applyTo(containerComposite);
+
+		eeTreeViewer = new CheckboxTreeViewer(containerComposite, SWT.SINGLE | SWT.H_SCROLL | SWT.V_SCROLL | SWT.BORDER);
+		eeTreeViewer.setContentProvider(new GrammarContentProvider());
+		eeTreeViewer.setLabelProvider(new GrammarLabelProvider());
+		GridDataFactory.fillDefaults().grab(true, true).applyTo(eeTreeViewer.getControl());
+
+		// add a listener to allow only one default EE
+		eeTreeViewer.addCheckStateListener(new ICheckStateListener() {
+			@Override
+			public void checkStateChanged(CheckStateChangedEvent event) {
+				String grammar = (String) event.getElement();
+				if (event.getChecked()) {
+					// allow to check only one element of the table
+					eeTreeViewer.setCheckedElements(new Object[] { grammar });
+					getPreferenceStore().setValue(PreferenceInitializer.GRAMMAR_DEFAULT_ID, grammar);
+				} else {
+					// removing the default ee from pref
+					getPreferenceStore().setValue(PreferenceInitializer.GRAMMAR_DEFAULT_ID, "none"); //$NON-NLS-1$
+				}
+				validateGrammar();
+			}
+		});
+
+		// ----------------
+		// Initialize UI
+		initializePage();
+		return containerComposite;
+	}
+
+	private void initializePage() {
+		if (eeTreeViewer == null || eeTreeViewer.getControl().isDisposed())
+			return;
+
+		// Refresh list
+		List<String> availableGrammars = LuaGrammarManager.getAvailableGrammars();
+		eeTreeViewer.setInput(availableGrammars);
+
+		// Set default interpreter
+		String defaultGrammar = getPreferenceStore().getString(PreferenceInitializer.GRAMMAR_DEFAULT_ID);
+		for (String grammar : availableGrammars) {
+			eeTreeViewer.setChecked(grammar, grammar.equals(defaultGrammar));
+		}
+	}
+
+	public void validateGrammar() {
+		if (eeTreeViewer.getCheckedElements().length == 0) {
+			setMessage(Messages.LuaGrammarPreferencePage_Warning_no_grammar, WARNING);
+			return;
+		}
+		setMessage(null);
+	}
+}
\ No newline at end of file
diff --git a/plugins/org.eclipse.ldt.ui/src/org/eclipse/ldt/ui/internal/preferences/Messages.java b/plugins/org.eclipse.ldt.ui/src/org/eclipse/ldt/ui/internal/preferences/Messages.java
index 426489d..41b0a9f 100644
--- a/plugins/org.eclipse.ldt.ui/src/org/eclipse/ldt/ui/internal/preferences/Messages.java
+++ b/plugins/org.eclipse.ldt.ui/src/org/eclipse/ldt/ui/internal/preferences/Messages.java
@@ -43,6 +43,8 @@
 	public static String LuaFormatterModifyDialogIndentation;
 	public static String LuaFoldingPreferencePage_initiallyFoldLevelOneBlocks;
 	public static String LuaFoldingPreferencePage_initiallyFoldDoc;
+	public static String LuaGrammarPreferencePage_page_description;
+	public static String LuaGrammarPreferencePage_Warning_no_grammar;
 	static {
 		// initialize resource bundle
 		NLS.initializeMessages(BUNDLE_NAME, Messages.class);
diff --git a/plugins/org.eclipse.ldt.ui/src/org/eclipse/ldt/ui/internal/preferences/messages.properties b/plugins/org.eclipse.ldt.ui/src/org/eclipse/ldt/ui/internal/preferences/messages.properties
index 79a4eed..6f757e7 100644
--- a/plugins/org.eclipse.ldt.ui/src/org/eclipse/ldt/ui/internal/preferences/messages.properties
+++ b/plugins/org.eclipse.ldt.ui/src/org/eclipse/ldt/ui/internal/preferences/messages.properties
@@ -35,4 +35,6 @@
 LuaFormatterModifyDialogIndentation=Indentation
 LuaFormatterIndentationTabPageTableIndentationPolicy=Table indentation policy
 LuaFoldingPreferencePage_initiallyFoldLevelOneBlocks=Blocks
-LuaFoldingPreferencePage_initiallyFoldDoc=LuaDocumentor Comments
\ No newline at end of file
+LuaFoldingPreferencePage_initiallyFoldDoc=LuaDocumentor Comments
+LuaGrammarPreferencePage_page_description=Select the default Lua grammar :
+LuaGrammarPreferencePage_Warning_no_grammar=No default Grammar.
diff --git a/plugins/org.eclipse.ldt.ui/src/org/eclipse/ldt/ui/internal/properties/GrammarPropertyPage.java b/plugins/org.eclipse.ldt.ui/src/org/eclipse/ldt/ui/internal/properties/GrammarPropertyPage.java
new file mode 100644
index 0000000..21e512a
--- /dev/null
+++ b/plugins/org.eclipse.ldt.ui/src/org/eclipse/ldt/ui/internal/properties/GrammarPropertyPage.java
@@ -0,0 +1,133 @@
+package org.eclipse.ldt.ui.internal.properties;
+
+import java.util.List;
+
+import org.eclipse.core.resources.IProject;
+import org.eclipse.core.resources.IResource;
+import org.eclipse.core.resources.ProjectScope;
+import org.eclipse.core.runtime.jobs.Job;
+import org.eclipse.dltk.core.SourceParserUtil;
+import org.eclipse.dltk.internal.ui.util.CoreUtility;
+import org.eclipse.jface.dialogs.IDialogConstants;
+import org.eclipse.jface.dialogs.MessageDialog;
+import org.eclipse.jface.layout.GridDataFactory;
+import org.eclipse.jface.layout.GridLayoutFactory;
+import org.eclipse.jface.viewers.ComboViewer;
+import org.eclipse.jface.viewers.ISelection;
+import org.eclipse.jface.viewers.IStructuredSelection;
+import org.eclipse.jface.viewers.StructuredSelection;
+import org.eclipse.ldt.core.internal.LuaLanguageToolkit;
+import org.eclipse.ldt.core.internal.PreferenceInitializer;
+import org.eclipse.ldt.core.internal.grammar.LuaGrammarManager;
+import org.eclipse.ldt.ui.internal.grammar.GrammarContentProvider;
+import org.eclipse.swt.SWT;
+import org.eclipse.swt.widgets.Composite;
+import org.eclipse.swt.widgets.Control;
+import org.eclipse.ui.IWorkbenchPropertyPage;
+import org.eclipse.ui.dialogs.PropertyPage;
+import org.eclipse.ui.preferences.IWorkbenchPreferenceContainer;
+import org.eclipse.ui.preferences.ScopedPreferenceStore;
+
+public class GrammarPropertyPage extends PropertyPage implements IWorkbenchPropertyPage {
+
+	private ComboViewer availableGrammarComboViewer;
+	private IProject project;
+
+	public GrammarPropertyPage() {
+	}
+
+	/**
+	 * Initializes a ProjectReferencePage.
+	 */
+	private void initialize() {
+		project = (IProject) getElement().getAdapter(IResource.class);
+		noDefaultAndApplyButton();
+		setDescription(Messages.GrammarPropertyPage_page_description);
+		if (project != null)
+			setPreferenceStore(new ScopedPreferenceStore(new ProjectScope(project), LuaLanguageToolkit.getDefault().getPreferenceQualifier()));
+	}
+
+	@Override
+	protected Control createContents(Composite parent) {
+		// Initialize class
+		initialize();
+
+		// ----------------
+		// CREATE CONTROL
+		// Create container composite
+		Composite containerComposite = new Composite(parent, SWT.NONE);
+		GridLayoutFactory.swtDefaults().margins(0, 0).numColumns(1).applyTo(containerComposite);
+		createDescriptionLabel(containerComposite);
+
+		// Grammar combo viewer
+		availableGrammarComboViewer = new ComboViewer(containerComposite, SWT.READ_ONLY | SWT.BORDER);
+		availableGrammarComboViewer.setContentProvider(new GrammarContentProvider());
+		GridDataFactory.swtDefaults().align(SWT.BEGINNING, SWT.BEGINNING).grab(true, false).applyTo(availableGrammarComboViewer.getControl());
+
+		// ----------------
+		// Initialize UI component
+		initializePage();
+		return containerComposite;
+	}
+
+	private void initializePage() {
+		if (availableGrammarComboViewer == null || availableGrammarComboViewer.getControl().isDisposed() || getPreferenceStore() == null)
+			return;
+
+		// Refresh list
+		List<String> availableGrammars = LuaGrammarManager.getAvailableGrammars();
+		availableGrammarComboViewer.setInput(availableGrammars);
+
+		// Set default interpreter
+		String defaultGrammar = getPreferenceStore().getString(PreferenceInitializer.GRAMMAR_DEFAULT_ID);
+		availableGrammarComboViewer.setSelection(new StructuredSelection(defaultGrammar));
+	}
+
+	public String getSelectedGrammar() {
+		ISelection selection = availableGrammarComboViewer.getSelection();
+		if (selection instanceof IStructuredSelection) {
+			Object firstElement = ((IStructuredSelection) selection).getFirstElement();
+			if (firstElement instanceof String)
+				return (String) firstElement;
+		}
+		return null;
+	}
+
+	@Override
+	public boolean performOk() {
+		// Get current values
+		String oldGrammar = getPreferenceStore().getString(PreferenceInitializer.GRAMMAR_DEFAULT_ID);
+		String newGrammar = getSelectedGrammar();
+
+		// Change preference
+		getPreferenceStore().setValue(PreferenceInitializer.GRAMMAR_DEFAULT_ID, newGrammar);
+
+		// Get workbench Container
+		IWorkbenchPreferenceContainer container = null;
+		if (getContainer() instanceof IWorkbenchPreferenceContainer)
+			container = (IWorkbenchPreferenceContainer) getContainer();
+
+		// rebuild project if needed
+		boolean needsBuild = oldGrammar != null && !oldGrammar.equals(newGrammar) && container != null;
+		boolean doBuild = false;
+		if (needsBuild) {
+			MessageDialog dialog = new MessageDialog(getShell(), Messages.GrammarPropertyPage_rebuild_dialog_title, null,
+					Messages.GrammarPropertyPage_rebuild_dialog_message, MessageDialog.QUESTION, new String[] { IDialogConstants.YES_LABEL,
+							IDialogConstants.NO_LABEL, IDialogConstants.CANCEL_LABEL }, 2);
+			int res = dialog.open();
+			if (res == 0) {
+				doBuild = true;
+			} else if (res != 1) {
+				return false; // cancel pressed
+			}
+		}
+
+		if (doBuild) { // post build
+			Job job = CoreUtility.getBuildJob(project);
+			// TODO we should not clear all the cache, but just the project one.
+			SourceParserUtil.clearCache();
+			container.registerUpdateJob(job);
+		}
+		return super.performOk();
+	}
+}
diff --git a/plugins/org.eclipse.ldt.ui/src/org/eclipse/ldt/ui/internal/properties/Messages.java b/plugins/org.eclipse.ldt.ui/src/org/eclipse/ldt/ui/internal/properties/Messages.java
new file mode 100644
index 0000000..06badd0
--- /dev/null
+++ b/plugins/org.eclipse.ldt.ui/src/org/eclipse/ldt/ui/internal/properties/Messages.java
@@ -0,0 +1,29 @@
+/*******************************************************************************
+ * Copyright (c) 2015 Sierra Wireless and others.
+ * 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:
+ *     Sierra Wireless - initial API and implementation
+ *******************************************************************************/
+package org.eclipse.ldt.ui.internal.properties;
+
+import org.eclipse.osgi.util.NLS;
+
+// CHECKSTYLE NLS: OFF
+public class Messages extends NLS {
+	private static final String BUNDLE_NAME = "org.eclipse.ldt.ui.internal.properties.messages"; //$NON-NLS-1$
+	public static String GrammarPropertyPage_page_description;
+	public static String GrammarPropertyPage_rebuild_dialog_message;
+	public static String GrammarPropertyPage_rebuild_dialog_title;
+	static {
+		// initialize resource bundle
+		NLS.initializeMessages(BUNDLE_NAME, Messages.class);
+	}
+
+	private Messages() {
+	}
+}
+// CHECKSTYLE NLS: ON
\ No newline at end of file
diff --git a/plugins/org.eclipse.ldt.ui/src/org/eclipse/ldt/ui/internal/properties/messages.properties b/plugins/org.eclipse.ldt.ui/src/org/eclipse/ldt/ui/internal/properties/messages.properties
new file mode 100644
index 0000000..92cbf57
--- /dev/null
+++ b/plugins/org.eclipse.ldt.ui/src/org/eclipse/ldt/ui/internal/properties/messages.properties
@@ -0,0 +1,3 @@
+GrammarPropertyPage_page_description=Define the grammar to use for code validation and keyword highlight :
+GrammarPropertyPage_rebuild_dialog_message=A grammar settings have changed. A rebuild of the project is required for changes to take effect. Build the project now ?
+GrammarPropertyPage_rebuild_dialog_title=Grammar Settings Changed
diff --git a/plugins/org.eclipse.ldt.ui/src/org/eclipse/ldt/ui/wizards/LuaProjectCreator.java b/plugins/org.eclipse.ldt.ui/src/org/eclipse/ldt/ui/wizards/LuaProjectCreator.java
index 1de7b7d..a7e4e61 100644
--- a/plugins/org.eclipse.ldt.ui/src/org/eclipse/ldt/ui/wizards/LuaProjectCreator.java
+++ b/plugins/org.eclipse.ldt.ui/src/org/eclipse/ldt/ui/wizards/LuaProjectCreator.java
@@ -23,10 +23,12 @@
 import org.eclipse.core.resources.IFile;
 import org.eclipse.core.resources.IFolder;
 import org.eclipse.core.resources.IProject;
+import org.eclipse.core.resources.ProjectScope;
 import org.eclipse.core.runtime.CoreException;
 import org.eclipse.core.runtime.IPath;
 import org.eclipse.core.runtime.IProgressMonitor;
 import org.eclipse.core.runtime.SubProgressMonitor;
+import org.eclipse.core.runtime.preferences.IEclipsePreferences;
 import org.eclipse.dltk.core.DLTKCore;
 import org.eclipse.dltk.core.IBuildpathEntry;
 import org.eclipse.dltk.ui.wizards.ILocationGroup;
@@ -35,9 +37,12 @@
 import org.eclipse.jface.wizard.IWizardPage;
 import org.eclipse.ldt.core.LuaConstants;
 import org.eclipse.ldt.core.buildpath.LuaExecutionEnvironment;
+import org.eclipse.ldt.core.internal.LuaLanguageToolkit;
+import org.eclipse.ldt.core.internal.PreferenceInitializer;
 import org.eclipse.ldt.core.internal.buildpath.LuaExecutionEnvironmentBuildpathUtil;
 import org.eclipse.ldt.ui.internal.Activator;
 import org.eclipse.ldt.ui.wizards.pages.LuaProjectSettingsPage;
+import org.osgi.service.prefs.BackingStoreException;
 
 public class LuaProjectCreator extends ProjectCreator {
 
@@ -58,6 +63,10 @@
 		ProjectCreateStep createSourceFolderStep = createSourceFolderStep();
 		if (createSourceFolderStep != null)
 			addStep(IProjectCreateStep.KIND_FINISH, 0, createSourceFolderStep, (IWizardPage) locationGroup);
+
+		ProjectCreateStep setGrammarStep = createGrammarStep();
+		if (setGrammarStep != null)
+			addStep(IProjectCreateStep.KIND_FINISH, 0, setGrammarStep, (IWizardPage) locationGroup);
 	}
 
 	/**
@@ -123,6 +132,23 @@
 		return entries.toArray(new IBuildpathEntry[entries.size()]);
 	}
 
+	private class SetGrammarStep extends ProjectCreateStep {
+
+		@Override
+		public void execute(IProject project, IProgressMonitor monitor) throws CoreException, InterruptedException {
+			String grammar = luaProjectSettingPage.getGrammar();
+			try {
+				IEclipsePreferences node = new ProjectScope(project).getNode(LuaLanguageToolkit.getDefault().getPreferenceQualifier());
+				node.put(PreferenceInitializer.GRAMMAR_DEFAULT_ID, grammar);
+				node.flush();
+			} catch (BackingStoreException e) {
+				Activator.logError(MessageFormat.format("Unable store grammar version {0} for project {1}", grammar, project.getName()), e); //$NON-NLS-1$
+			}
+			monitor.done();
+		}
+
+	}
+
 	/**
 	 * Creates a default file named LuaWizardContants.DEFAULT_MAIN_FILE in default source folder.
 	 */
@@ -200,4 +226,8 @@
 	protected ProjectCreateStep createSourceFolderStep() {
 		return new CreateDefaultSourceFolderProjectCreateStep();
 	}
+
+	protected ProjectCreateStep createGrammarStep() {
+		return new SetGrammarStep();
+	}
 }
diff --git a/plugins/org.eclipse.ldt.ui/src/org/eclipse/ldt/ui/wizards/pages/GrammarGroup.java b/plugins/org.eclipse.ldt.ui/src/org/eclipse/ldt/ui/wizards/pages/GrammarGroup.java
new file mode 100644
index 0000000..4e927c3
--- /dev/null
+++ b/plugins/org.eclipse.ldt.ui/src/org/eclipse/ldt/ui/wizards/pages/GrammarGroup.java
@@ -0,0 +1,87 @@
+/*******************************************************************************
+ * Copyright (c) 2015 Sierra Wireless and others.
+ * 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:
+ *     Sierra Wireless - initial API and implementation
+ *******************************************************************************/
+package org.eclipse.ldt.ui.wizards.pages;
+
+import java.util.List;
+
+import org.eclipse.core.runtime.preferences.InstanceScope;
+import org.eclipse.jface.layout.GridDataFactory;
+import org.eclipse.jface.layout.GridLayoutFactory;
+import org.eclipse.jface.viewers.ComboViewer;
+import org.eclipse.jface.viewers.ISelection;
+import org.eclipse.jface.viewers.IStructuredSelection;
+import org.eclipse.jface.viewers.StructuredSelection;
+import org.eclipse.ldt.core.internal.LuaLanguageToolkit;
+import org.eclipse.ldt.core.internal.PreferenceInitializer;
+import org.eclipse.ldt.core.internal.grammar.LuaGrammarManager;
+import org.eclipse.ldt.ui.internal.grammar.GrammarContentProvider;
+import org.eclipse.swt.SWT;
+import org.eclipse.swt.widgets.Composite;
+import org.eclipse.swt.widgets.Display;
+import org.eclipse.swt.widgets.Group;
+import org.eclipse.ui.preferences.ScopedPreferenceStore;
+
+public class GrammarGroup {
+
+	private ComboViewer availableGrammarComboViewer;
+	private ISelection selection;
+
+	public GrammarGroup(final Composite parent) {
+		// Create group
+		final Group group = new Group(parent, SWT.NONE);
+		group.setText(Messages.GrammarGroup_group_name);
+		GridDataFactory.swtDefaults().align(SWT.FILL, SWT.CENTER).applyTo(group);
+		GridLayoutFactory.swtDefaults().numColumns(1).applyTo(group);
+
+		// Grammar combo viewer
+		availableGrammarComboViewer = new ComboViewer(group, SWT.READ_ONLY | SWT.BORDER);
+		availableGrammarComboViewer.setContentProvider(new GrammarContentProvider());
+		GridDataFactory.swtDefaults().align(SWT.BEGINNING, SWT.BEGINNING).grab(true, false).applyTo(availableGrammarComboViewer.getControl());
+
+		initializeGroup();
+	}
+
+	public String getSelectedGrammar() {
+		Display.getDefault().syncExec(new Runnable() {
+			public void run() {
+				if (availableGrammarComboViewer != null) {
+					selection = availableGrammarComboViewer.getSelection();
+				} else {
+					selection = null;
+				}
+			}
+		});
+
+		if (selection instanceof IStructuredSelection) {
+			Object firstElement = ((IStructuredSelection) selection).getFirstElement();
+			if (firstElement instanceof String)
+				return (String) firstElement;
+		}
+
+		return null;
+	}
+
+	private void initializeGroup() {
+		if (availableGrammarComboViewer == null || availableGrammarComboViewer.getControl().isDisposed())
+			return;
+
+		// Refresh list
+		List<String> availableGrammars = LuaGrammarManager.getAvailableGrammars();
+		availableGrammarComboViewer.setInput(availableGrammars);
+
+		// Set default interpreter
+		ScopedPreferenceStore preferenceStore = new ScopedPreferenceStore(InstanceScope.INSTANCE, LuaLanguageToolkit.getDefault()
+				.getPreferenceQualifier());
+		String defaultGrammar = preferenceStore.getString(PreferenceInitializer.GRAMMAR_DEFAULT_ID);
+		if (defaultGrammar != null)
+			availableGrammarComboViewer.setSelection(new StructuredSelection(defaultGrammar));
+	}
+}
diff --git a/plugins/org.eclipse.ldt.ui/src/org/eclipse/ldt/ui/wizards/pages/LuaProjectSettingsPage.java b/plugins/org.eclipse.ldt.ui/src/org/eclipse/ldt/ui/wizards/pages/LuaProjectSettingsPage.java
index 5632082..88c8351 100644
--- a/plugins/org.eclipse.ldt.ui/src/org/eclipse/ldt/ui/wizards/pages/LuaProjectSettingsPage.java
+++ b/plugins/org.eclipse.ldt.ui/src/org/eclipse/ldt/ui/wizards/pages/LuaProjectSettingsPage.java
@@ -27,6 +27,7 @@
 public class LuaProjectSettingsPage extends ProjectWizardFirstPage implements Observer {
 
 	private LuaExecutionEnvironmentGroup luaExecutionEnvironmentGroup;
+	private GrammarGroup grammarGroup;
 
 	public LuaProjectSettingsPage() {
 		setTitle(Messages.LuaProjecSettingsPageLabel);
@@ -55,11 +56,15 @@
 
 	protected void createCustomGroups(final Composite composite) {
 		luaExecutionEnvironmentGroup = createExecutionEnvironmentGroup(composite);
+		grammarGroup = createGrammarGroup(composite);
+	}
+
+	protected GrammarGroup createGrammarGroup(Composite composite) {
+		return new GrammarGroup(composite);
 	}
 
 	protected LuaExecutionEnvironmentGroup createExecutionEnvironmentGroup(final Composite composite) {
-		final LuaExecutionEnvironmentGroup eeGroup = new LuaExecutionEnvironmentGroup(composite);
-		return eeGroup;
+		return new LuaExecutionEnvironmentGroup(composite);
 	}
 
 	/**
@@ -79,6 +84,12 @@
 		return null;
 	}
 
+	public String getGrammar() {
+		if (grammarGroup != null)
+			return grammarGroup.getSelectedGrammar();
+		return null;
+	}
+
 	/**
 	 * 
 	 * @deprecated Use hasToCreateTemplate() instead.
diff --git a/plugins/org.eclipse.ldt.ui/src/org/eclipse/ldt/ui/wizards/pages/Messages.java b/plugins/org.eclipse.ldt.ui/src/org/eclipse/ldt/ui/wizards/pages/Messages.java
index da091c6..337c966 100644
--- a/plugins/org.eclipse.ldt.ui/src/org/eclipse/ldt/ui/wizards/pages/Messages.java
+++ b/plugins/org.eclipse.ldt.ui/src/org/eclipse/ldt/ui/wizards/pages/Messages.java
@@ -31,6 +31,8 @@
 	/** @since 1.2 */
 	public static String DocLuaFilePage_title;
 
+	public static String GrammarGroup_group_name;
+
 	/** @since 1.1 */
 	public static String LuaExecutionEnvironmentGroupTemplateLabel;
 
diff --git a/plugins/org.eclipse.ldt.ui/src/org/eclipse/ldt/ui/wizards/pages/messages.properties b/plugins/org.eclipse.ldt.ui/src/org/eclipse/ldt/ui/wizards/pages/messages.properties
index f3452db..7565732 100644
--- a/plugins/org.eclipse.ldt.ui/src/org/eclipse/ldt/ui/wizards/pages/messages.properties
+++ b/plugins/org.eclipse.ldt.ui/src/org/eclipse/ldt/ui/wizards/pages/messages.properties
@@ -14,6 +14,7 @@
 ConvertToLuaProjectMainPage_migrationMessage=You will migrate a koneki project to new Lua project. This can not be undone.
 DocLuaFilePage_description=Create a DocLua file. A DocLua file is a file describing an API to\nenable tooling, and will not be taken in account at runtime.
 DocLuaFilePage_title=DocLua File
+GrammarGroup_group_name=Target Grammar
 LuaExecutionEnvironmentGroupMainLabel=Create default template project ready to run.
 LuaExecutionEnvironmentGroupTemplateLabel=Create default template project ready to run.
 LuaExecutionEnvironmentGroupManageExecutionEnvironment=Configure Execution Environments...
diff --git a/plugins/org.eclipse.ldt/META-INF/MANIFEST.MF b/plugins/org.eclipse.ldt/META-INF/MANIFEST.MF
index 11cdbb1..118447f 100644
--- a/plugins/org.eclipse.ldt/META-INF/MANIFEST.MF
+++ b/plugins/org.eclipse.ldt/META-INF/MANIFEST.MF
@@ -2,7 +2,7 @@
 Bundle-ManifestVersion: 2
 Bundle-Name: %Bundle-Name
 Bundle-SymbolicName: org.eclipse.ldt;singleton:=true
-Bundle-Version: 1.2.0.qualifier
+Bundle-Version: 1.3.0.qualifier
 Bundle-Activator: org.eclipse.ldt.core.internal.Activator
 Bundle-Vendor: %Bundle-Vendor
 Require-Bundle: org.eclipse.ui;bundle-version="3.5.0",
@@ -17,6 +17,7 @@
 Bundle-ActivationPolicy: lazy
 Export-Package: org.eclipse.ldt.core,
  org.eclipse.ldt.core.buildpath,
+ org.eclipse.ldt.core.grammar,
  org.eclipse.ldt.core.internal;
   x-friends:="org.eclipse.ldt.core.tests,
    org.eclipse.ldt.debug.core,
@@ -67,6 +68,7 @@
    org.eclipse.ldt.debug.core,
    org.eclipse.ldt.debug.ui,
    org.eclipse.ldt.ui",
+ org.eclipse.ldt.core.internal.grammar,
  org.eclipse.ldt.core.internal.todo;
   x-friends:="org.eclipse.ldt.core.tests,
    org.eclipse.ldt.debug.core,
diff --git a/plugins/org.eclipse.ldt/OSGI-INF/l10n/bundle.properties b/plugins/org.eclipse.ldt/OSGI-INF/l10n/bundle.properties
index 98ec9e0..b36344c 100644
--- a/plugins/org.eclipse.ldt/OSGI-INF/l10n/bundle.properties
+++ b/plugins/org.eclipse.ldt/OSGI-INF/l10n/bundle.properties
@@ -14,3 +14,4 @@
 Bundle-Name = Lua Development Tools Core
 Bundle-Vendor = Eclipse LDT
 extension-point.executionenvironement.name = Execution Environment
+extension-point.luagrammar.name = Lua Grammar
\ No newline at end of file
diff --git a/plugins/org.eclipse.ldt/plugin.xml b/plugins/org.eclipse.ldt/plugin.xml
index be4d33d..872d890 100644
--- a/plugins/org.eclipse.ldt/plugin.xml
+++ b/plugins/org.eclipse.ldt/plugin.xml
@@ -12,6 +12,7 @@
 
 <plugin>
    <extension-point id="executionEnvironment" name="%extension-point.executionenvironement.name" schema="schema/executionEnvironment.exsd"/>
+   <extension-point id="luaGrammar" name="%extension-point.luagrammar.name" schema="schema/luaGrammar.exsd"/>
    <extension
          id="nature"
          name="%extension.name"
diff --git a/plugins/org.eclipse.ldt/pom.xml b/plugins/org.eclipse.ldt/pom.xml
index 5d97712..89b5dce 100644
--- a/plugins/org.eclipse.ldt/pom.xml
+++ b/plugins/org.eclipse.ldt/pom.xml
@@ -19,7 +19,7 @@
   </parent>
   <groupId>org.eclipse.ldt</groupId>
   <artifactId>org.eclipse.ldt</artifactId>
-  <version>1.2.0-SNAPSHOT</version>
+  <version>1.3.0-SNAPSHOT</version>
   <packaging>eclipse-plugin</packaging>
   
   <build>
diff --git a/plugins/org.eclipse.ldt/schema/luaGrammar.exsd b/plugins/org.eclipse.ldt/schema/luaGrammar.exsd
new file mode 100644
index 0000000..76dbbe9
--- /dev/null
+++ b/plugins/org.eclipse.ldt/schema/luaGrammar.exsd
@@ -0,0 +1,116 @@
+<?xml version='1.0' encoding='UTF-8'?>
+<!-- Schema file written by PDE -->
+<schema targetNamespace="org.eclipse.ldt" xmlns="http://www.w3.org/2001/XMLSchema">
+<annotation>
+      <appinfo>
+         <meta.schema plugin="org.eclipse.ldt" id="luaGrammar" name="Lua Grammar"/>
+      </appinfo>
+      <documentation>
+         Allow to register a grammar for Lua.
+      </documentation>
+   </annotation>
+
+   <element name="extension">
+      <annotation>
+         <appinfo>
+            <meta.element />
+         </appinfo>
+      </annotation>
+      <complexType>
+         <sequence minOccurs="1" maxOccurs="unbounded">
+            <element ref="grammar"/>
+         </sequence>
+         <attribute name="point" type="string" use="required">
+            <annotation>
+               <documentation>
+                  
+               </documentation>
+            </annotation>
+         </attribute>
+         <attribute name="id" type="string">
+            <annotation>
+               <documentation>
+                  
+               </documentation>
+            </annotation>
+         </attribute>
+         <attribute name="name" type="string">
+            <annotation>
+               <documentation>
+                  
+               </documentation>
+               <appinfo>
+                  <meta.attribute translatable="true"/>
+               </appinfo>
+            </annotation>
+         </attribute>
+      </complexType>
+   </element>
+
+   <element name="grammar">
+      <complexType>
+         <attribute name="name" type="string" use="required">
+            <annotation>
+               <documentation>
+                  
+               </documentation>
+            </annotation>
+         </attribute>
+         <attribute name="validator" type="string" use="required">
+            <annotation>
+               <documentation>
+                  
+               </documentation>
+               <appinfo>
+                  <meta.attribute kind="java" basedOn=":org.eclipse.ldt.core.ILuaSourceValidator"/>
+               </appinfo>
+            </annotation>
+         </attribute>
+         <attribute name="keywords" type="string">
+            <annotation>
+               <documentation>
+                  Grammar keywords separated with comma.
+               </documentation>
+            </annotation>
+         </attribute>
+      </complexType>
+   </element>
+
+   <annotation>
+      <appinfo>
+         <meta.section type="since"/>
+      </appinfo>
+      <documentation>
+         [Enter the first release in which this extension point appears.]
+      </documentation>
+   </annotation>
+
+   <annotation>
+      <appinfo>
+         <meta.section type="examples"/>
+      </appinfo>
+      <documentation>
+         [Enter extension point usage example here.]
+      </documentation>
+   </annotation>
+
+   <annotation>
+      <appinfo>
+         <meta.section type="apiinfo"/>
+      </appinfo>
+      <documentation>
+         [Enter API information here.]
+      </documentation>
+   </annotation>
+
+   <annotation>
+      <appinfo>
+         <meta.section type="implementation"/>
+      </appinfo>
+      <documentation>
+         [Enter information about supplied implementation of this extension point.]
+      </documentation>
+   </annotation>
+
+
+</schema>
diff --git a/plugins/org.eclipse.ldt/script/local/javamodelsbuilder.lua b/plugins/org.eclipse.ldt/script/local/javamodelsbuilder.lua
index 5953f01..b381778 100644
--- a/plugins/org.eclipse.ldt/script/local/javamodelsbuilder.lua
+++ b/plugins/org.eclipse.ldt/script/local/javamodelsbuilder.lua
@@ -25,106 +25,12 @@
 -- 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)
+-- @param LuaSourceRoot, DLTK node, root of DLTK AST
+function M.build(source, modulename, root)
 
   -- 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 )
 
@@ -152,7 +58,6 @@
   -- TODO clean perf profiling
   -- local e = os.clock()
   -- print ('global time', type(e), type(s),(e*1000-s*1000))
-  return root
 end
 
 return M
diff --git a/plugins/org.eclipse.ldt/src/org/eclipse/ldt/core/grammar/IGrammar.java b/plugins/org.eclipse.ldt/src/org/eclipse/ldt/core/grammar/IGrammar.java
new file mode 100644
index 0000000..dfa8cba
--- /dev/null
+++ b/plugins/org.eclipse.ldt/src/org/eclipse/ldt/core/grammar/IGrammar.java
@@ -0,0 +1,23 @@
+/*******************************************************************************
+ * Copyright (c) 2014 Sierra Wireless and others.
+ * 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:
+ *     Sierra Wireless - initial API and implementation
+ *******************************************************************************/
+package org.eclipse.ldt.core.grammar;
+
+import java.util.List;
+
+public interface IGrammar {
+
+	String getName();
+
+	ILuaSourceValidator getValidator();
+
+	List<String> getKeywords();
+
+}
diff --git a/plugins/org.eclipse.ldt/src/org/eclipse/ldt/core/grammar/ILuaSourceValidator.java b/plugins/org.eclipse.ldt/src/org/eclipse/ldt/core/grammar/ILuaSourceValidator.java
new file mode 100644
index 0000000..eb74e63
--- /dev/null
+++ b/plugins/org.eclipse.ldt/src/org/eclipse/ldt/core/grammar/ILuaSourceValidator.java
@@ -0,0 +1,23 @@
+/*******************************************************************************
+ * Copyright (c) 2014 Sierra Wireless and others.
+ * 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:
+ *     Sierra Wireless - initial API and implementation
+ *******************************************************************************/
+package org.eclipse.ldt.core.grammar;
+
+
+public interface ILuaSourceValidator {
+
+	boolean valid(String source);
+
+	String getCleanedSource();
+
+	String getErrorMessage();
+
+	int getLineIndex();
+}
diff --git a/plugins/org.eclipse.ldt/src/org/eclipse/ldt/core/internal/PreferenceInitializer.java b/plugins/org.eclipse.ldt/src/org/eclipse/ldt/core/internal/PreferenceInitializer.java
index 93dc228..5c1f98a 100644
--- a/plugins/org.eclipse.ldt/src/org/eclipse/ldt/core/internal/PreferenceInitializer.java
+++ b/plugins/org.eclipse.ldt/src/org/eclipse/ldt/core/internal/PreferenceInitializer.java
@@ -17,6 +17,9 @@
 public class PreferenceInitializer extends AbstractPreferenceInitializer {
 
 	public static final String EE_DEFAULT_ID = "EE__default_id"; //$NON-NLS-1$
+	public static final String EE_DEFAULT_ID_VALUE = "lua-5.1"; //$NON-NLS-1$
+	public static final String GRAMMAR_DEFAULT_ID = "Grammar__default_id"; //$NON-NLS-1$
+	public static final String GRAMMAR_DEFAULT_ID_VALUE = "lua-5.1"; //$NON-NLS-1$
 	public static final String USE_GLOBAL_VAR_IN_LDT = "USE_GLOBAL_VAR_IN_LDT"; //$NON-NLS-1$
 
 	@Override
@@ -24,7 +27,8 @@
 		ScopedPreferenceStore preferenceStore = new ScopedPreferenceStore(DefaultScope.INSTANCE, LuaLanguageToolkit.getDefault()
 				.getPreferenceQualifier());
 
-		preferenceStore.setDefault(EE_DEFAULT_ID, "lua-5.1"); //$NON-NLS-1$
+		preferenceStore.setDefault(EE_DEFAULT_ID, EE_DEFAULT_ID_VALUE);
+		preferenceStore.setDefault(GRAMMAR_DEFAULT_ID, GRAMMAR_DEFAULT_ID_VALUE);
 		preferenceStore.setDefault(USE_GLOBAL_VAR_IN_LDT, true);
 	}
 }
diff --git a/plugins/org.eclipse.ldt/src/org/eclipse/ldt/core/internal/ast/parser/LuaSourceParser.java b/plugins/org.eclipse.ldt/src/org/eclipse/ldt/core/internal/ast/parser/LuaSourceParser.java
index 04a69c1..8d51b2b 100644
--- a/plugins/org.eclipse.ldt/src/org/eclipse/ldt/core/internal/ast/parser/LuaSourceParser.java
+++ b/plugins/org.eclipse.ldt/src/org/eclipse/ldt/core/internal/ast/parser/LuaSourceParser.java
@@ -14,6 +14,12 @@
 import java.util.Hashtable;
 import java.util.Map;
 
+import org.eclipse.core.resources.IProject;
+import org.eclipse.core.resources.ProjectScope;
+import org.eclipse.core.runtime.CoreException;
+import org.eclipse.core.runtime.Platform;
+import org.eclipse.core.runtime.preferences.IScopeContext;
+import org.eclipse.core.runtime.preferences.InstanceScope;
 import org.eclipse.dltk.ast.ASTNode;
 import org.eclipse.dltk.ast.parser.AbstractSourceParser;
 import org.eclipse.dltk.ast.parser.IModuleDeclaration;
@@ -25,14 +31,20 @@
 import org.eclipse.dltk.core.IElementChangedListener;
 import org.eclipse.dltk.core.IModelElement;
 import org.eclipse.dltk.core.IModelElementDelta;
+import org.eclipse.dltk.core.IScriptProject;
 import org.eclipse.jface.text.BadLocationException;
 import org.eclipse.jface.text.Document;
 import org.eclipse.ldt.core.LuaUtils;
+import org.eclipse.ldt.core.grammar.IGrammar;
+import org.eclipse.ldt.core.grammar.ILuaSourceValidator;
 import org.eclipse.ldt.core.internal.Activator;
+import org.eclipse.ldt.core.internal.LuaLanguageToolkit;
+import org.eclipse.ldt.core.internal.PreferenceInitializer;
 import org.eclipse.ldt.core.internal.ast.models.LuaDLTKModelUtils;
 import org.eclipse.ldt.core.internal.ast.models.api.LuaFileAPI;
 import org.eclipse.ldt.core.internal.ast.models.common.LuaSourceRoot;
 import org.eclipse.ldt.core.internal.ast.models.file.LuaInternalContent;
+import org.eclipse.ldt.core.internal.grammar.LuaGrammarManager;
 import org.eclipse.osgi.util.NLS;
 
 /**
@@ -110,31 +122,41 @@
 
 		synchronized (LuaSourceParser.class) {
 			try {
-				// remove Byte Order Mark :
+				// Remove Byte Order Mark :
 				if (source.startsWith("\ufeff")) { //$NON-NLS-1$
 					source = source.substring(1);
 				}
 
-				// Build AST
-				module = astBuilder.buildAST(source, moduleName);
+				// Valid source code
+				ILuaSourceValidator sourceValidator = getValidator(getProject(input));
+				if (sourceValidator == null) {
+					Activator.logWarning(NLS.bind("No validator found for input {0}.", input.getFileName())); //$NON-NLS-1$
+					module.setProblem(1, 1, 0, 0, "No validator have have been found for this file."); //$NON-NLS-1$
+				} else {
+					boolean valid = sourceValidator.valid(source);
+					String cleanedSource = sourceValidator.getCleanedSource();
+					if (!valid)
+						module.setProblem(sourceValidator.getLineIndex(), -1, -1, -1, sourceValidator.getErrorMessage());
 
-				// Fix AST
-				if (module != null)
+					// Build AST
+					if (cleanedSource != null)
+						astBuilder.buildAST(cleanedSource, moduleName, module);
+
+					// Fix AST
 					module.traverse(new EncodingVisitor(fixer));
+				}
 			}
 			// CHECKSTYLE:OFF
 			catch (final Exception e) {
 				// CHECKSTYLE:ON
 				Activator.logWarning(NLS.bind("Unable to parse file {0}.", input.getFileName()), e); //$NON-NLS-1$
 				// the module is probably on error.
-				if (module == null)
-					module = new LuaSourceRoot(source.length());
 				module.setProblem(1, 1, 0, 0, "This file probably contains a syntax error."); //$NON-NLS-1$
 			}
 
 			// Deal with errors on Lua side
 			if (module != null) {
-				// if module contains a syntax error
+				// If module contains a syntax error
 				if (module.hasError()) {
 					// add error to reporter
 					final DefaultProblem problem = module.getProblem();
@@ -182,4 +204,35 @@
 		}
 		return module;
 	}
+
+	private ILuaSourceValidator getValidator(IProject project) throws CoreException {
+		// Create context
+		IScopeContext[] context;
+		if (project != null)
+			context = new IScopeContext[] { new ProjectScope(project), InstanceScope.INSTANCE };
+		else
+			context = new IScopeContext[] { InstanceScope.INSTANCE };
+
+		// Get grammarName
+		String grammarName = Platform.getPreferencesService().getString(LuaLanguageToolkit.getDefault().getPreferenceQualifier(),
+				PreferenceInitializer.GRAMMAR_DEFAULT_ID, PreferenceInitializer.GRAMMAR_DEFAULT_ID_VALUE, context);
+
+		// Get grammar
+		IGrammar grammar = LuaGrammarManager.getAvailableGrammar(grammarName);
+		if (grammar != null)
+			return grammar.getValidator();
+		return null;
+	}
+
+	private IProject getProject(IModuleSource input) {
+		if (input == null)
+			return null;
+		IModelElement modelElement = input.getModelElement();
+		if (modelElement == null)
+			return null;
+		IScriptProject scriptProject = modelElement.getScriptProject();
+		if (scriptProject == null)
+			return null;
+		return scriptProject.getProject();
+	}
 }
diff --git a/plugins/org.eclipse.ldt/src/org/eclipse/ldt/core/internal/ast/parser/ModelsBuilderLuaModule.java b/plugins/org.eclipse.ldt/src/org/eclipse/ldt/core/internal/ast/parser/ModelsBuilderLuaModule.java
index 74dae28..d3ac6ef 100644
--- a/plugins/org.eclipse.ldt/src/org/eclipse/ldt/core/internal/ast/parser/ModelsBuilderLuaModule.java
+++ b/plugins/org.eclipse.ldt/src/org/eclipse/ldt/core/internal/ast/parser/ModelsBuilderLuaModule.java
@@ -34,7 +34,7 @@
 

 	private LuaState lua = null;

 

-	public synchronized LuaSourceRoot buildAST(final String source, final String modulename) {

+	public synchronized void buildAST(final String source, final String modulename, final LuaSourceRoot root) {

 		if (lua == null)

 			lua = loadLuaModule();

 

@@ -42,13 +42,11 @@
 		lua.getField(-1, "build"); //$NON-NLS-1$

 		lua.pushString(source);

 		lua.pushString(modulename);

-		lua.call(2, 1);

-		LuaSourceRoot luaSourceRoot = lua.checkJavaObject(-1, LuaSourceRoot.class);

-		lua.pop(2);

+		lua.pushJavaObject(root);

+		lua.call(3, 0);

+		lua.pop(1);

 

 		// lua.close();

-

-		return luaSourceRoot;

 	}

 

 	/**

diff --git a/plugins/org.eclipse.ldt/src/org/eclipse/ldt/core/internal/grammar/LuaGrammarManager.java b/plugins/org.eclipse.ldt/src/org/eclipse/ldt/core/internal/grammar/LuaGrammarManager.java
new file mode 100644
index 0000000..1e1f5be
--- /dev/null
+++ b/plugins/org.eclipse.ldt/src/org/eclipse/ldt/core/internal/grammar/LuaGrammarManager.java
@@ -0,0 +1,107 @@
+/*******************************************************************************
+ * Copyright (c) 2014 Sierra Wireless and others.
+ * 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:
+ *     Sierra Wireless - initial API and implementation
+ *******************************************************************************/
+package org.eclipse.ldt.core.internal.grammar;
+
+import java.util.ArrayList;
+import java.util.List;
+
+import org.eclipse.core.runtime.CoreException;
+import org.eclipse.core.runtime.IConfigurationElement;
+import org.eclipse.core.runtime.Platform;
+import org.eclipse.ldt.core.grammar.IGrammar;
+import org.eclipse.ldt.core.grammar.ILuaSourceValidator;
+
+public final class LuaGrammarManager {
+
+	private static final String EXTENSION_POINT_ID = "org.eclipse.ldt.luaGrammar"; //$NON-NLS-1$
+	private static final String ATTRIBUTE_NAME = "name"; //$NON-NLS-1$
+	private static final String ATTRIBUTE_VALIDATOR = "validator"; //$NON-NLS-1$
+	private static final String ATTRIBUTE_KEYWORDS = "keywords"; //$NON-NLS-1$
+	private static final String KEYWORDS_SEPARATOR = ","; //$NON-NLS-1$
+
+	private LuaGrammarManager() {
+	}
+
+	private static IConfigurationElement getGrammarContribution(String name) throws CoreException {
+		if (name == null)
+			return null;
+
+		// search plug-in contribution
+		IConfigurationElement[] contributions = Platform.getExtensionRegistry().getConfigurationElementsFor(EXTENSION_POINT_ID);
+		for (int i = 0; i < contributions.length; i++) {
+			String nameAttribute = contributions[i].getAttribute(ATTRIBUTE_NAME);
+
+			if (name.equals(nameAttribute)) {
+				return contributions[i];
+			}
+		}
+		return null;
+	}
+
+	private static IGrammar getGrammarFromContribution(final String name) throws CoreException {
+		// search plug-in contribution
+		IConfigurationElement grammarContribution = getGrammarContribution(name);
+		if (grammarContribution != null) {
+
+			final ILuaSourceValidator validator = (ILuaSourceValidator) grammarContribution.createExecutableExtension(ATTRIBUTE_VALIDATOR);
+
+			final String keywordsAttribute = grammarContribution.getAttribute(ATTRIBUTE_KEYWORDS);
+			final List<String> keywords = new ArrayList<String>();
+			if (keywordsAttribute != null) {
+				for (String word : keywordsAttribute.split(KEYWORDS_SEPARATOR)) {
+					// TODO validate the keyword ? no special char, ...
+					String cleanWord = word.trim();
+					if (!cleanWord.isEmpty())
+						keywords.add(cleanWord);
+				}
+			}
+
+			return new IGrammar() {
+
+				@Override
+				public ILuaSourceValidator getValidator() {
+					return validator;
+				}
+
+				@Override
+				public String getName() {
+					return name;
+				}
+
+				@Override
+				public List<String> getKeywords() {
+					return keywords;
+				}
+			};
+		}
+		return null;
+	}
+
+	public static IGrammar getAvailableGrammar(String name) throws CoreException {
+		return getGrammarFromContribution(name);
+	}
+
+	public static List<String> getAvailableGrammars() {
+		List<String> grammars = new ArrayList<String>();
+
+		// search plug-in contribution
+		IConfigurationElement[] contributions = Platform.getExtensionRegistry().getConfigurationElementsFor(EXTENSION_POINT_ID);
+		for (int i = 0; i < contributions.length; i++) {
+			String nameAttribute = contributions[i].getAttribute(ATTRIBUTE_NAME);
+
+			if (nameAttribute != null && !nameAttribute.isEmpty()) {
+				grammars.add(nameAttribute);
+			}
+		}
+
+		return grammars;
+	}
+}
diff --git a/tests/org.eclipse.ldt.core.tests/META-INF/MANIFEST.MF b/tests/org.eclipse.ldt.core.tests/META-INF/MANIFEST.MF
index 3abe6e3..d8300c8 100644
--- a/tests/org.eclipse.ldt.core.tests/META-INF/MANIFEST.MF
+++ b/tests/org.eclipse.ldt.core.tests/META-INF/MANIFEST.MF
@@ -9,7 +9,8 @@
  org.junit;bundle-version="4.5.0",
  org.eclipse.core.resources;bundle-version="3.6.0",
  org.eclipse.dltk.core;bundle-version="[5.0.0,6.0.0)",
- org.eclipse.ldt;bundle-version="0.9.0"
+ org.eclipse.ldt;bundle-version="0.9.0",
+ org.eclipse.ldt.support.lua51;bundle-version="1.1.0"
 Bundle-RequiredExecutionEnvironment: JavaSE-1.6
 Bundle-ActivationPolicy: lazy
 Export-Package: org.eclipse.ldt.core.tests,
diff --git a/tests/org.eclipse.ldt.lua.tests/tests/formatter/input/basic/longstring2.lua b/tests/org.eclipse.ldt.lua.tests/tests/formatter/input/basic/longstring2.lua
index 4272aa7..6c06fed 100644
--- a/tests/org.eclipse.ldt.lua.tests/tests/formatter/input/basic/longstring2.lua
+++ b/tests/org.eclipse.ldt.lua.tests/tests/formatter/input/basic/longstring2.lua
@@ -4,4 +4,4 @@
 local longString = [=[Long string
     4 space at the start of this line
 4 space at the end of this line    
-]=]
+]=]
\ No newline at end of file
diff --git a/tests/org.eclipse.ldt.metalua.tests/src/org/eclipse/ldt/metalua/tests/internal/cases/TestMetalua.java b/tests/org.eclipse.ldt.metalua.tests/src/org/eclipse/ldt/metalua/tests/internal/cases/TestMetalua.java
index e61ff9f..d04762a 100644
--- a/tests/org.eclipse.ldt.metalua.tests/src/org/eclipse/ldt/metalua/tests/internal/cases/TestMetalua.java
+++ b/tests/org.eclipse.ldt.metalua.tests/src/org/eclipse/ldt/metalua/tests/internal/cases/TestMetalua.java
@@ -138,6 +138,18 @@
 		}
 	}
 
+	/** Run from source */
+	public void testlua52() {
+		try {
+			final StringBuffer sb = new StringBuffer("local mlc = require ('metalua.compiler').new()\n"); //$NON-NLS-1$ 
+			sb.append("ast = mlc:src_to_ast[[goto a\nprint 'hello'\n::a::]]"); //$NON-NLS-1$ 
+			state.load(sb.toString(), "metaluaCode"); //$NON-NLS-1$ 
+			state.call(0, 0);
+		} catch (LuaException e) {
+			fail(e.getMessage());
+		}
+	}
+
 	public void testSourcesPath() {
 		String path = Metalua.path();
 		assertFalse("Metalua sources path is not definded.", path.isEmpty());//$NON-NLS-1$